Я знаю, що це давнє запитання, але є кілька речей, яких, здається, усім не вистачає.
По-перше, це множення на 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, це було б зроблено у векторному класі С ++ (і багатьох інших місцях) десятиліття тому.
Нарешті, якщо ви дійсно хочете оптимізувати, не потійте дрібниці. Зараз вже ніхто не дбає про те, щоб витратити 4 КБ пам’яті, якщо він не працює над вбудованими системами. Коли ви потрапляєте до 1 ГБ об’єктів, розмір яких від 1 МБ до 10 МБ, подвоєння, мабуть, занадто велике (я маю на увазі, це від 100 до 1000 об’єктів). Якщо ви можете оцінити очікуваний темп розширення, ви можете вирівняти його до лінійного темпу зростання в певний момент. Якщо ви очікуєте приблизно 10 об’єктів на хвилину, то вирощування з 5 до 10 розмірів об’єкта на крок (раз на 30 секунд до хвилини), мабуть, добре.
До чого все зводиться, це не передумуйте, оптимізуйте те, що можете, і, якщо потрібно, налаштуйте під свою програму (і платформу).