W jaki sposób malloc() jest implementowane wewnętrznie? [duplikat]

To pytanie ma już odpowiedź tutaj:

Czy ktoś może wyjaśnić jak malloc() działa wewnętrznie?

Czasami robiłem strace program i widzę wiele sbrk wywołań systemowych, robiąc man sbrk mówi o tym, że jest używany w malloc(), ale niewiele więcej.

Author: orlp, 2010-08-13

3 answers

Wywołanie systemowe sbrk przesuwa "obramowanie" segmentu danych. Oznacza to, że przesuwa obramowanie obszaru, w którym program może odczytywać/zapisywać dane (pozwalając mu rosnąć lub kurczyć się, chociaż AFAIK no malloc naprawdę oddaje segmenty pamięci z powrotem do jądra za pomocą tej metody). Poza tym, istnieje również mmap, który jest używany do mapowania plików do pamięci, ale jest również używany do przydzielania pamięci (jeśli chcesz przydzielić pamięć współdzieloną, mmap to jak to robisz).

Więc masz dwie metody, aby uzyskać więcej pamięć z jądra: sbrk i mmap. Istnieją różne strategie, jak zorganizować pamięć, którą masz z jądra.

Naiwnym sposobem jest podział go na strefy, często nazywane "wiadrami", które są dedykowane określonym rozmiarom konstrukcji. Na przykład implementacja malloc może tworzyć wiadra dla struktur 16, 64, 256 i 1024 bajtów. Jeśli poprosisz malloc o podanie pamięci o danym rozmiarze to zaokrągli tę liczbę do następnego rozmiaru, a następnie poda ci element z to wiadro. Jeśli potrzebujesz większego obszaru malloc, możesz użyć mmap do alokacji bezpośrednio z jądrem. Jeśli wiadro o określonym rozmiarze jest puste malloc może użyć sbrk, aby uzyskać więcej miejsca na nowe wiadro.

Istnieją różne projekty malloc i prawdopodobnie nie ma jednego prawdziwego sposobu implementacji malloc, ponieważ musisz osiągnąć kompromis między szybkością, kosztami i unikaniem fragmentacji / efektywności przestrzeni. Na przykład, jeśli w zasobniku zabraknie elementów, implementacja może pobrać element z większe wiadro, podziel je i dodaj do wiadra, w którym zabrakło elementów. Byłoby to dość oszczędne miejsce, ale nie byłoby możliwe przy każdym projekcie. Jeśli dostaniesz kolejne wiadro przez sbrk/mmap może to być szybsze i jeszcze łatwiejsze, ale nie tak oszczędne miejsce. Ponadto projekt musi oczywiście wziąć pod uwagę, że "wolny" musi w jakiś sposób udostępnić przestrzeń malloc. Nie rozdaje się pamięci bez ponownego użycia.

Jeśli jesteś zainteresowany, OpenSER / Kamailio SIP proxy ma dwie implementacje malloc (potrzebują własnej, ponieważ intensywnie wykorzystują pamięć współdzieloną, a system malloc nie obsługuje pamięci współdzielonej). Zobacz: https://github.com/OpenSIPS/opensips/tree/master/mem

Wtedy moglibyście rzucić okiem na GNU libcmalloc implementację , ale ta jest bardzo skomplikowana, IIRC.

 91
Author: DarkDust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-11 08:40:07

W uproszczeniu malloc i darmowa praca w ten sposób:

Malloc zapewnia dostęp do sterty procesu. Sterta jest konstrukcją w bibliotece C (popularnie libc), która pozwala obiektom na uzyskanie wyłącznego dostępu do pewnej przestrzeni na stercie procesu.

Każdy przydział na stercie nazywa się komórką sterty. Zazwyczaj składa się z nagłówka, który zawiera informacje o rozmiarze komórki, a także wskaźnik do następnej komórki stosu. To sprawia, że sterta skutecznie łączy lista.

Gdy rozpoczyna się proces, sterta zawiera pojedynczą komórkę, która zawiera całą przestrzeń sterty przypisaną podczas uruchamiania. Ta komórka istnieje na wolnej liście sterty.

Gdy ktoś wywołuje malloca, pamięć jest pobierana z dużej komórki sterty, która jest zwracana przez malloca. Reszta jest uformowana w nową komórkę sterty, która składa się z całej reszty pamięci.

Gdy zwalnia się pamięć, komórka sterty jest dodawana na końcu listy wolnej sterty. Kolejne malloki chodzą po darmowej liście Szukam komórki o odpowiedniej wielkości.

Jak można się spodziewać, sterta może zostać fragmentowana, a menedżer sterty może od czasu do czasu próbować scalić sąsiadujące komórki sterty.

Gdy na wolnej liście nie ma pamięci dla żądanej alokacji, malloc wywołuje brk lub sbrk, które są wywołaniami systemowymi wymagającymi więcej stron pamięci z systemu operacyjnego.

Teraz jest kilka modyfikacji w celu optymalizacji operacji sterty.

  • dla dużych alokacji pamięci (zazwyczaj > 512 bajtów, sterta manager może przejść prosto do systemu operacyjnego i przydziel pełną stronę pamięci.
  • the heap może określić minimalny rozmiar alokacja w celu zapobiegania dużym kwotom fragmentacji.
  • sterta może również podzielić się na pojemniki jeden dla małych przydziałów i jeden dla większych przydziałów, aby większe przydziały szybciej.
  • istnieją również sprytne mechanizmy optymalizacji wielowątkowej alokacji sterty.
 41
Author: doron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-13 18:09:53

Ważne jest również, aby zdać sobie sprawę, że po prostu przesunięcie wskaźnika przerwania programu za pomocą brk i sbrk w rzeczywistości nie przydziela Pamięci, tylko ustawia przestrzeń adresową. Na przykład w Linuksie pamięć będzie "wspierana" przez rzeczywiste fizyczne strony, gdy dostęp do tego zakresu adresów jest dostępny, co spowoduje błąd strony i ostatecznie doprowadzi do wywołania jądra do alokatora stron w celu uzyskania strony wspierającej.

 7
Author: mgalgs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-16 21:09:11