Wiem, że to stare pytanie, ale jest kilka rzeczy, których każdemu wydaje się brakować.
Po pierwsze, to jest mnożenie przez 2: rozmiar << 1. To jest mnożenie przez cokolwiek z przedziału od 1 do 2: int (float (rozmiar) * x), gdzie x to liczba, * to matematyka zmiennoprzecinkowa, a procesor aby uruchomić dodatkowe instrukcje rzutowania między float i int. Innymi słowy, na poziomie maszyny podwojenie wymaga jednej, bardzo szybkiej instrukcji, aby znaleźć nowy rozmiar. Mnożenie przez coś między 1 a 2 wymaga co najmniejjedna instrukcja rzutowania rozmiaru na zmiennoprzecinkową, jedna instrukcja mnożenia (czyli mnożenie przez liczbę zmiennoprzecinkową, więc prawdopodobnie zajmuje co najmniej dwa razy więcej cykli, jeśli nie 4, a nawet 8 razy więcej) i jedna instrukcja rzutowania z powrotem na int, a to zakłada, że Twoja platforma może wykonywać obliczenia zmiennoprzecinkowe na rejestrach ogólnego przeznaczenia, zamiast wymagać użycia specjalnych rejestrów. Krótko mówiąc, należy oczekiwać, że obliczenia matematyczne dla każdego przydziału będą trwały co najmniej 10 razy dłużej niż zwykłe przesunięcie w lewo. Jeśli jednak kopiujesz dużo danych podczas ponownego przydziału, może to nie mieć większego znaczenia.
Po drugie, i prawdopodobnie wielki kicker: każdy wydaje się zakładać, że uwalniana pamięć jest zarówno ciągła ze sobą, jak i sąsiadująca z nowo przydzieloną pamięcią. O ile sam nie przydzielasz wstępnie całej pamięci, a następnie nie używasz jej jako puli, prawie na pewno tak nie jest. System operacyjny może czasamiw końcu tak się stanie, ale przez większość czasu będzie wystarczająco dużo wolnego miejsca, aby każdy w połowie przyzwoity system zarządzania pamięcią był w stanie znaleźć małą dziurę, w której zmieści się twoja pamięć. Gdy dojdziesz do naprawdę ugryzionych kawałków, bardziej prawdopodobne jest, że skończysz z ciągłymi fragmentami, ale do tego czasu twoje przydziały są na tyle duże, że nie robisz ich wystarczająco często, aby miało to już znaczenie. Krótko mówiąc, fajnie jest sobie wyobrazić, że użycie jakiejś idealnej liczby pozwoli na najbardziej efektywne wykorzystanie wolnego miejsca w pamięci, ale w rzeczywistości tak się nie stanie, chyba że twój program będzie działał na czystym metalu (ponieważ nie ma systemu operacyjnego pod nim podejmowanie wszystkich decyzji).
Moja odpowiedź na pytanie? Nie, nie ma idealnej liczby. Jest tak specyficzny dla aplikacji, że nikt nawet nie próbuje. Jeśli Twoim celem jest idealne wykorzystanie pamięci, nie masz szczęścia. Dla wydajności lepsze są alokacje rzadziej, ale gdybyśmy poszli tylko z tym, moglibyśmy pomnożyć przez 4 lub nawet 8! Oczywiście, gdy Firefox przeskakuje z 1 GB do 8 GB za jednym razem, ludzie będą narzekać, więc to nawet nie ma sensu. Oto kilka praktycznych zasad, którymi bym się kierował:
Jeśli nie możesz zoptymalizować użycia pamięci, przynajmniej nie marnuj cykli procesora. Mnożenie przez 2 jest co najmniej o rząd wielkości szybsze niż wykonywanie obliczeń zmiennoprzecinkowych. Może nie będzie to wielka różnica, ale przynajmniej trochę zmieni (szczególnie na początku, podczas częstszych i mniejszych przydziałów).
Nie myśl za dużo. Jeśli właśnie spędziłeś 4 godziny, próbując dowiedzieć się, jak zrobić coś, co już zostało zrobione, po prostu zmarnowałeś swój czas. Szczerze mówiąc, gdyby istniała lepsza opcja niż * 2, zostałaby wykonana w klasie wektorowej C ++ (i wielu innych miejscach) dziesiątki lat temu.
Wreszcie, jeśli naprawdę chcesz zoptymalizować, nie przejmuj się drobiazgami. W dzisiejszych czasach nikt nie przejmuje się marnowaniem 4KB pamięci, chyba że pracuje na systemach wbudowanych. Gdy dojdziesz do 1 GB obiektów, które mają od 1 MB do 10 MB każdy, podwojenie jest prawdopodobnie zbyt duże (mam na myśli od 100 do 1000 obiektów). Jeśli potrafisz oszacować oczekiwany współczynnik ekspansji, możesz wyrównać go do liniowego tempa wzrostu w pewnym momencie. Jeśli spodziewasz się około 10 obiektów na minutę, to wzrost o 5 do 10 rozmiarów obiektów na krok (raz na 30 sekund do minuty) jest prawdopodobnie w porządku.
Wszystko sprowadza się do tego, że nie przemyślaj tego, zoptymalizuj, co możesz, i dostosuj do swojej aplikacji (i platformy), jeśli musisz.