Я знаю, что это старый вопрос, но есть несколько вещей, которые всем, кажется, не хватает.
Во-первых, это умножение на 2: size << 1. Это умножение на что-либо от 1 до 2: int (float (size) * x), где x - это число, * - математика с плавающей запятой, а процессор имеет для запуска дополнительных инструкций по приведению типов между float и int. Другими словами, на машинном уровне для поиска нового размера для удвоения требуется одна очень быстрая инструкция. Для умножения на значение от 1 до 2 требуется как минимумодна инструкция для преобразования размера в число с плавающей запятой, одна инструкция для умножения (это умножение с плавающей запятой, поэтому, вероятно, потребуется как минимум в два раза больше циклов, если не в 4 или даже в 8 раз больше) и одна инструкция для возврата к int, и это предполагает, что ваша платформа может выполнять вычисления с плавающей запятой в регистрах общего назначения, вместо того, чтобы требовать использования специальных регистров. Короче говоря, вы должны ожидать, что математика для каждого распределения займет как минимум в 10 раз больше времени, чем простой сдвиг влево. Если вы копируете много данных во время перераспределения, это не может иметь большого значения.
Во-вторых, и это, вероятно, самый важный момент: все, кажется, полагают, что освобождаемая память является смежной с самой собой, а также с недавно выделенной памятью. Если вы заранее не распределяете всю память, а затем используете ее как пул, это почти наверняка не так. ОС может иногдав конечном итоге это произойдет, но в большинстве случаев фрагментации свободного пространства будет достаточно, чтобы любая полуприличная система управления памятью смогла найти небольшую дыру, в которой ваша память просто поместится. Как только вы доберетесь до действительно битовых блоков, у вас больше шансов получить непрерывные части, но к тому времени ваши выделения будут достаточно большими, чтобы вы не выполняли их достаточно часто, чтобы это больше не имело значения. Короче говоря, забавно представить, что использование некоторого идеального числа позволит наиболее эффективно использовать свободное пространство памяти, но на самом деле этого не произойдет, если ваша программа не будет работать на голом железе (например, нет ОС под ним принимаются все решения).
Мой ответ на вопрос? Нет, идеального числа не существует. Это настолько специфично для приложения, что никто даже не пытается. Если ваша цель - идеальное использование памяти, вам в значительной степени не повезло. Для производительности лучше использовать менее частое распределение, но если бы мы пошли именно так, мы могли бы умножить на 4 или даже на 8! Конечно, когда Firefox перескакивает с 1 ГБ на 8 ГБ за один раз, люди будут жаловаться, так что это даже не имеет смысла. Вот несколько практических правил, которые я бы придерживался:
Если вы не можете оптимизировать использование памяти, по крайней мере, не теряйте циклы процессора. Умножение на 2 по крайней мере на порядок быстрее, чем вычисления с плавающей запятой. Это может не иметь большого значения, но, по крайней мере, будет иметь какое-то значение (особенно на ранних этапах, при более частом и меньшем распределении).
Не зацикливайтесь на этом. Если вы потратили 4 часа, пытаясь понять, как сделать что-то, что уже было сделано, вы просто зря потратили время. Честно говоря, если бы был вариант лучше, чем * 2, это было бы сделано в векторном классе C ++ (и во многих других местах) несколько десятилетий назад.
Наконец, если вы действительно хотите оптимизировать, не переживайте по мелочам. В наши дни никого не волнует потеря 4 КБ памяти, если только они не работают со встроенными системами. Когда вы получаете 1 ГБ объектов размером от 1 до 10 МБ каждый, удвоение, вероятно, слишком много (я имею в виду, что это от 100 до 1000 объектов). Если вы можете оценить ожидаемую скорость расширения, вы можете выровнять ее до линейной скорости роста в определенный момент. Если вы ожидаете около 10 объектов в минуту, то увеличение размера от 5 до 10 объектов за шаг (от 30 секунд до минуты), вероятно, будет нормальным.
Все сводится к тому, что не думайте слишком много, оптимизируйте то, что вы можете, и при необходимости настраивайте свое приложение (и платформу).