Masz rację, to częsty problem [Edycja: jak zrobić przydzielanie o stałej wielkości, mam na myśli. "malloc
spowalnia moją aplikację" jest mniej powszechne niż mogłoby ci się wydawać.
Jeśli Twój kod jest zbyt wolny, a malloc
wiarygodnym winowajcą, to prosty przydział komórek (lub "pula pamięci") może poprawić sytuację. Niemal na pewno możesz go gdzieś znaleźć lub łatwo napisać:
Przydziel duży blok i umieść pojedynczy węzeł na początku każdej 16-bajtowej komórki. Połącz je wszystkie razem.Aby przydzielić, zdejmij głowę z listy i zwróć ją. Aby zwolnić, dodaj komórkę do nagłówka listy. Oczywiście, jeśli spróbujesz przydzielić i lista jest pusta, musisz przydzielić nowy duży blok, podzielić go na komórki i dodać wszystkie do wolnej listy.
Możesz tego uniknąć, jeśli chcesz. Po przydzieleniu dużego bloku, po prostu przechowuj wskaźnik na jego końcu. Aby przydzielić, przenieś wskaźnik o 16 bajtów przez blok i zwróć nową wartość. Chyba że był już na początku bloku [*], oczywiście. Jeśli tak się stanie, a wolna lista jest pusta, potrzebujesz nowego dużego bloku. Bezpłatne nie zmienia się - wystarczy dodać węzeł do bezpłatnej listy.
Masz opcję, czy najpierw wyjść z bloku, i sprawdzić listę darmową, jeśli jest wyczerpana, lub najpierw sprawdzić wolną listę i zlikwidować blok, jeśli jest pusty. Nie wiem, który wydaje się być szybszy - dobrą rzeczą w ostatniej darmowej liście jest to, że jest ona przyjazna dla pamięci podręcznej, ponieważ używasz pamięci, która była ostatnio używana, więc prawdopodobnie spróbowałbym tego pierwszy.
Należy zauważyć, że węzeł listy nie jest potrzebny, gdy komórka jest przydzielona, więc zasadniczo narzut na komórkę wynosi zero. Całkiem poza szybkością, jest to prawdopodobnie przewaga nad malloc
lub innymi alokatorami ogólnego przeznaczenia.
Należy pamiętać, że upuszczenie całego przydziału jest w zasadzie jedynym sposobem zwalniania pamięci z powrotem do systemu, więc użytkownicy, którzy planują przydzielić dużo komórek, korzystać z nich i uwolnić ich wszystkich, powinni utworzyć własne alokator, użyj go, a następnie zniszcz. Zarówno dla wydajności (nie musisz zwolnić wszystkich komórek), jak i dla zapobieżenia efektowi fragmentacji, w którym cały blok musi być zachowany, jeśli którakolwiek z jego komórek jest w użyciu. Jeśli nie możesz tego zrobić, twoje wykorzystanie pamięci będzie znaczącą wartością wody w czasie, w którym program był uruchomiony. W przypadku niektórych programów, które stanowią problem (na przykład długotrwały program ze sporadycznymi dużymi skokami w użyciu pamięci, w systemie, w którym pamięć jest ograniczona). Dla innych jest to absolutnie w porządku (na przykład, jeśli liczba używanych komórek zwiększa się do bardzo bliskiej końca programu lub zmienia się w zakresie, w którym naprawdę nie obchodzi cię, że zużywasz więcej pamięci, niż to możliwe). Dla niektórych jest to pożądane (jeśli wiesz, ile pamięci chcesz użyć, możesz przydzielić wszystko z góry i nie musisz się martwić o awarie). W związku z tym niektóre implementacje z malloc
mają trudności z przywracaniem pamięci z procesu do systemu operacyjnego.
[*] Gdzie "początek bloku" prawdopodobnie oznacza "początek bloku, plus rozmiar jakiegoś węzła używanego do utrzymania listy wszystkich bloków, dzięki czemu wszystkie mogą zostać uwolnione, gdy alokator komórek jest zniszczony".
Czy trzeba tę pamięć „jeden strzał”, jak mówią, z jakiegoś algorytmu albo zrobisz to na przebieg programuje czas życia (który może być bardzo długi?) – Skurmedel
Jednym z kryteriów przy tworzeniu biblioteki alokacji jest to, jak dobrze będzie ona działała w tego rodzaju okolicznościach, a nawet w środowiskach nieprzyjaznych. Podczas implementowania niestandardowych procedur alokacji jest dobra zabawa, prawdopodobnie nie potrzebujesz tego. –
@Skurmedel - wiele małych bitów pamięci zostanie zamówionych i zwolnionych podczas wykonywania programu. – mmmmalloc