GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum ruft malloc() mmap() und brk() austauschbar auf?

mmap (bei Verwendung mit MAP_ANONYMOUS ) weist einen Teil des RAM zu, der irgendwo im virtuellen Adressraum des Prozesses platziert werden kann und der später wieder freigegeben werden kann (mit munmap ) unabhängig von allen anderen Zuordnungen.

brk ändert die Endadresse einer einzelnen, zusammenhängenden "Arena" des virtuellen Adressraums:Wenn diese Adresse erhöht wird, weist sie der Arena mehr Speicher zu, und wenn sie verringert wird, wird der Speicher am Ende der Arena freigegeben. Daher wird Speicher mit brk zugewiesen kann erst wieder an das Betriebssystem freigegeben werden, wenn ein zusammenhängender Adressbereich am Ende der Arena steht wird vom Prozess nicht mehr benötigt.

Mit brk für kleine Zuordnungen und mmap für große Zuweisungen ist eine Heuristik, die auf der Annahme basiert, dass kleine Zuweisungen mit größerer Wahrscheinlichkeit alle dieselbe Lebensdauer haben, während große Zuweisungen eher eine Lebensdauer haben, die nicht mit der Lebensdauer anderer Zuweisungen korreliert. Große Zuweisungen verwenden also das Systemprimitiv, mit dem sie unabhängig von allem anderen freigegeben werden können, und kleine Zuweisungen verwenden das Primitive, das dies nicht tut.

Diese Heuristik ist nicht sehr zuverlässig. Die aktuelle Generation von malloc Implementierungen hat, wenn ich mich recht erinnere, auf brk ganz aufgegeben und verwendet mmap für alles. Die malloc Ich vermute, dass die Implementierung, die Sie sich ansehen (die in der GNU C-Bibliothek, basierend auf Ihren Tags) sehr alt ist und hauptsächlich weiterhin verwendet wird, weil niemand mutig genug ist, das Risiko einzugehen, sie gegen etwas Neueres auszutauschen, das wahrscheinlich aber nicht sicher besser sein.


Warum also malloc mmap aufruft, wenn es darum geht, eine große Speichergröße zuzuweisen?

Die kurze Antwort lautet für verbesserte Effizienz auf neueren Implementierungen von Linux und den aktualisierten Speicherzuweisungsalgorithmen, die mit ihnen geliefert werden. Denken Sie jedoch daran, dass dies ein sehr implementierungsabhängiges Thema ist und das Warum und Warum für unterschiedliche Jahrgänge und Geschmacksrichtungen des spezifischen Linux-Betriebssystems, das diskutiert wird, stark variieren würde.

Hier ist eine ziemlich neue Beschreibung bezüglich der Low-Level-Teile mmap() und brk() Spiel in der Linux-Speicherzuweisung. Und ein nicht so aktueller, aber immer noch relevanter Artikel im Linux Journal, der einige Inhalte enthält, die für das Thema hier sehr aktuell sind, einschließlich dieser:

Bei sehr großen Anfragen verwendet malloc() den Systemaufruf mmap(), um adressierbaren Speicherplatz zu finden. Dieser Prozess trägt dazu bei, die negativen Auswirkungen der Speicherfragmentierung zu reduzieren wenn große Speicherblöcke freigegeben, aber durch kleinere, kürzlich zugewiesene Blöcke gesperrt werden, die zwischen ihnen und dem Ende des zugewiesenen Speicherplatzes liegen. In diesem Fall wäre der Block, wenn er mit brk() zugewiesen worden wäre, für das System unbrauchbar geblieben, selbst wenn der Prozess ihn freigegeben hätte.
(Hervorhebung von mir)

Bezüglich brk() :
übrigens "...mmap() existierte in den frühen Versionen von Unix nicht. brk() war damals die einzige Möglichkeit, das Datensegment des Prozesses zu vergrößern. Die erste Unix-Version mit mmap() war Mitte der 80er Jahre SunOS, die erste Open-Source-Version war 1990 BSD-Reno. ". Seit dieser Zeit wurde die moderne Implementierung von Speicherzuweisungsalgorithmen mit vielen Verbesserungen überarbeitet, wodurch die Notwendigkeit für sie, die Verwendung von brk() einzubeziehen, erheblich reduziert wurde .


Linux
  1. Was ist ein Linux-Server und warum benötigt Ihr Unternehmen einen?

  2. Speicherüberwachung und -verwaltung

  3. Warum schlägt sed mit internationalen Zeichen fehl und wie kann man das beheben?

  4. Warum ist mmap() schneller als sequentielles IO?

  5. Was macht 'set -e' und warum könnte es als gefährlich angesehen werden?

Was ist der Grep-Befehl unter Linux? Warum wird es verwendet und wie funktioniert es?

Wann wird ein Signal behandelt und warum frieren einige Informationen ein?

Warum zeigt mein System nur 3,2 GiB RAM an, wenn ich definitiv 4,0 GiB habe

Warum verwenden Debian und Ubuntu standardmäßig Runlevel 2?

Warum ändert sich MemTotal in /proc/meminfo?

Warum unterscheiden sich Linux-Systemrufnummern in x86 und x86_64?