6 Stimmen

Linux Memory-mapped-Dateien reservieren viel physischen Speicher.

Ich habe ein Problem, das in mehreren Threads zum Thema Memory-Mapping und einem wachsenden Speicherverbrauch unter Linux beschrieben wurde.

Wenn ich eine 1GB-Datei unter Linux oder MacOS X öffne und sie in den Speicher mappe, indem ich

me.data_begin = mmap(NULL, Kapazität(me), prot, MAP_SHARED, me.file.handle, 0);

und den gemappten Speicher sequenziell lese, verwendet mein Programm immer mehr physischen Speicher, obwohl ich posix_madvise verwendet habe (es sogar mehrmals während des Lesevorgangs aufgerufen habe):

posix_madvise(me.data_begin, Kapazität(me), MMAP_SEQUENTIAL);

ohne Erfolg. :-(

Ich habe versucht:

  • unterschiedliche Flags MMAP_RANDOM, MMAP_DONTNEED, MMAP_NORMAL ohne Erfolg
  • posix_fadvise(me.file.handle, 0, Kapazität(me), POSIX_FADV_DONTNEED) vor und nach dem Aufruf von mmap -> kein Erfolg

Es funktioniert unter Mac OS X !!! wenn ich

posix_madvise(... MMAP_SEQUENTIAL)

und

msync(me.data_begin, Kapazität(me), MS_INVALIDATE).

kombiniere. Der im Speicher gehaltene Speicher beträgt weniger als 16M (ich habe msync periodisch nach 16 Mio. Schritten aufgerufen).

Aber unter Linux funktioniert nichts. Hat jemand eine Idee oder eine Erfolgsgeschichte für mein Problem unter Linux?

Viele Grüße, David

11voto

Juliano Punkte 35709

Die Speicherverwaltung unter Linux unterscheidet sich von anderen Systemen. Das Schlüsselprinzip ist, dass ungenutzter Speicher verschwendeter Speicher ist. Linux versucht auf viele Arten, die Speicherauslastung zu maximieren, was (meistens) zu einer besseren Leistung führt.

Es geht nicht darum, dass in Linux "gar nichts funktioniert", sondern dass sein Verhalten etwas anders ist als erwartet.

Wenn Speicherseiten aus der mmapped-Datei geholt werden, muss das Betriebssystem entscheiden, welche physischen Speicherseiten es freigeben (oder auslagern) soll, um sie zu nutzen. Es wird nach Seiten gesucht, die leichter ausgelagert werden können (kein sofortiger Festplattenzugriff erforderlich) und die weniger wahrscheinlich erneut verwendet werden.

Der POSIX-Aufruf madvice() dient dazu, dem System mitzuteilen, wie Ihre Anwendung die Seiten verwenden wird. Aber wie der Name sagt, handelt es sich um einen Rat, damit das Betriebssystem bessere Entscheidungen bei der Umleitung und beim Auslagern von Seiten treffen kann. Es ist weder eine Richtlinie noch ein Befehl.

Um die Auswirkungen von madvice() auf Linux zu demonstrieren, habe ich eine Übung, die ich meinen Schülern gebe, modifiziert. Sehen Sie sich den vollständigen Quellcode hier an. Mein System ist 64-Bit und hat 2 GB RAM, von denen derzeit etwa 50% verwendet werden. Mit dem Programm wird eine 2 GB große Datei gemappt, sequenziell gelesen und alles verworfen. Es wird alle 200 MB gelesenen RSS-Verbrauch gemeldet. Die Ergebnisse ohne madvice():

 ~% ./madvtest file.dat n
     0 :     3 MB
   200 :   202 MB
   400 :   402 MB
   600 :   602 MB
   800 :   802 MB
  1000 :  1002 MB
  1200 :  1066 MB
  1400 :  1068 MB
  1600 :  1078 MB
  1800 :  1113 MB
  2000 :  1113 MB

Linux hat Dinge aus dem Speicher gedrängt, bis etwa 1 GB gelesen wurde. Danach begann es, den Prozess selbst zu belasten (da die anderen 50% des Speichers von anderen Prozessen aktiv waren) und stabilisierte sich bis zum Ende der Datei.

Jetzt, mit madvice():

 ~% ./madvtest file.dat y
     0 :     3 MB
   200 :   202 MB
   400 :   402 MB
   600 :   494 MB
   800 :   501 MB
  1000 :   518 MB
  1200 :   530 MB
  1400 :   530 MB
  1600 :   530 MB
  1800 :   595 MB
  2000 :   788 MB

Beachten Sie, dass Linux entschieden hat, dem Prozess nur bis zu etwa 500 MB zuzuweisen, wesentlich früher als ohne madvice(). Dies liegt daran, dass die Seiten, die sich bereits im Speicher befinden, wesentlich wertvoller erschienen als die Seiten, die von diesem Prozess als sequenzieller Zugriff markiert wurden. Es gibt einen Schwellenwert im VMM, der festlegt, wann alte Seiten aus dem Prozess entfernt werden sollen.

Sie könnten sich fragen, warum Linux Seiten bis etwa 500 MB zugeordnet hat und nicht viel früher gestoppt hat, da sie als sequenzieller Zugriff markiert wurden. Entweder hatte das System sowieso genügend freie Speicherseiten oder die anderen residenten Seiten waren zu alt, um noch beizubehalten. Zwischen dem Behalten alter Seiten im Speicher, die anscheinend nicht mehr nützlich sind, und dem Bereitstellen neuer Seiten für ein Programm, das gerade läuft, wählt Linux die zweite Option.

Auch wenn sie als sequenzieller Zugriff markiert waren, war es nur ein Rat. Die Anwendung kann immer noch zu diesen Seiten zurückkehren und sie erneut lesen. Oder eine andere Anwendung im System. Der madvice() -Aufruf sagt nur, was die Anwendung selbst tut, Linux berücksichtigt das Gesamtbild.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X