2010-09-24 6 views
5

Ich habe ein Problem, das in mehreren Threads bezüglich Speicherabbildung und einem wachsenden Speicherverbrauch unter Linux beschrieben wurde.Linux Memory-Mapped-Dateien reservieren viel physischen Speicher

Wenn ich eine 1 GB-Datei unter Linux oder MacOS X öffnen und wo es sich in den Speicher mit

me.data_begin = mmap(NULL, capacity(me), prot, MAP_SHARED, me.file.handle, 0); 

und sequentiell gelesen das Map-Speicher, mein Programm immer mehr physischen Speicher verwendet, obwohl ich posix_madvise verwendet (auch genannt es mehrfach während des Lesevorgangs):

posix_madvise(me.data_begin, capacity(me), MMAP_SEQUENTIAL); 

ohne Erfolg.

:-(

Ich habe versucht:

  • verschiedene Flaggen MMAP_RANDOM, MMAP_DONTNEED, MMAP_NORMAL ohne Erfolg
  • posix_fadvise (me.file.handle, 0, Kapazität (me), POSIX_FADV_DONTNEED) vor und nach Mmap Aufruf -> kein Erfolg

Es unter Mac OS X funktioniert !!! wenn ich kombinieren

posix_madvise(.. MMAP_SEQUENTIAL) 

und

msync(me.data_begin, capacity(me), MS_INVALIDATE). 

Die residenten Speicher unter 16M (I msync nach 16Mio Schritte periodisch genannt).

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

Cheers, David

+0

Es kann oder möglicherweise nicht relevant sein, aber es sollte nützlich sein zu wissen: Verwenden Sie ein 32-Bit- oder 64-Bit-System? Ist Ihnen bewusst, dass Sie 1 GB in einem 32-Bit-System nicht mappen sollten? (Auch wenn Sie ein 64-Bit-System verwenden, können Sie sich um die Portabilität kümmern). – Juliano

+0

Alle Systeme sind 64-Bit (mit 64-Bit-Dateizeiger und Offsets) und ich konnte 40 GB-Dateien erfolgreich zuordnen. Ich habe das Problem aus Gründen der Reproduzierbarkeit auf 1 GB reduziert. – Dave

+0

@Sven. Es gibt Fälle, in denen eine Speicherzuordnung unumgänglich ist, beispielsweise wenn ein Bibliotheksaufruf eine Speicherregion und nicht eine Datei erfordert. Ihr Vorschlag ist also nicht hilfreich und beantwortet die Frage nicht. Zur Antwort, anscheinend auf Linux MMAP_SEQUENTIAL ist ziemlich * kaputt *. Der Vorausleseteil funktioniert, der Seitenwiederherstellungsteil nicht. Und die einzige Möglichkeit, Linux zu empfehlen, dass diese Seiten tatsächlich gute Kandidaten sind, besteht darin, die Region aufzulösen (und sie erneut zuzuordnen). –

Antwort

8

Linux-Speicherverwaltung von anderen Systemen unterscheidet. Das Schlüsselprinzip ist, dass Speicher, der nicht verwendet wird, Speicher verschwendet. In vielerlei Hinsicht versucht Linux, die Speichernutzung zu maximieren, was (meistens) zu einer besseren Leistung führt.

Es ist nicht, dass "nichts funktioniert" in Linux, aber dass sein Verhalten ein wenig anders ist, als Sie erwarten.

Wenn Speicherseiten aus der mmapped-Datei gezogen werden, muss das Betriebssystem entscheiden, welche physikalischen Speicherseiten es freigeben (oder auslagern) soll. Es wird nach Seiten gesucht, die leichter auswechselbar sind (erfordern kein sofortiges Schreiben auf der Festplatte) und werden wahrscheinlich seltener erneut verwendet.

Der POSIX-Aufruf madvice() dient dazu, dem System mitzuteilen, wie Ihre Anwendung die Seiten verwendet. Aber wie der Name sagt, ist es eine Beratung, so dass das Betriebssystem besser in Paging-und Swapping-Entscheidungen instrumentiert ist. Es ist weder eine Politik noch eine Bestellung.

Um die Auswirkungen von madvice() auf Linux zu demonstrieren, habe ich eine der Übungen geändert, die ich meinen Schülern gebe. Siehe complete source code here. Mein System ist 64-Bit und hat 2 GB RAM, was etwa 50% ist jetzt in Betrieb. Verwenden Sie das Programm, um eine 2-GB-Datei zu mappen, lesen Sie sie nacheinander und löschen Sie alles. Es meldet RSS-Nutzung alle 200 MB gelesen wird.Die Ergebnisse ohne madvice():

<[email protected]> ~% ./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 immer die Sachen aus dem Speicher bis etwa 1 GB lesen schieben wurde. Danach begann es, den Prozess selbst unter Druck zu setzen (da die anderen 50% des Speichers durch die anderen Prozesse aktiv waren) und stabilisierte sich bis zum Ende der Datei.

Nun mit madvice():

<[email protected]> ~% ./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-Seiten nur auf den Prozess zuzuteilen beschlossen, bis es rund 500 MB erreicht, viel früher als ohne madvice(). Dies ist darauf zurückzuführen, dass die im Speicher befindlichen Seiten danach viel wertvoller waren als die Seiten, die durch diesen Prozess als sequenzieller Zugriff markiert wurden. Es gibt einen Schwellenwert im VMM, der definiert, wann mit dem Löschen alter Seiten aus dem Prozess begonnen werden soll.

Sie fragen sich vielleicht, warum Linux Seiten bis zu 500 MB reserviert 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 sie zu behalten. Zwischen alten Seiten im Speicher, die nicht mehr nützlich zu sein scheinen, und weiteren Seiten, die einem Programm dienen, das jetzt ausführt, wählt Linux die zweite Option.

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

+0

Danke Juliano, dass 50% Verhalten ist interessant. Ich frage mich nur, warum es keine Möglichkeit gibt, Linux zu zwingen, Seiten freizugeben, die ich nie wieder lese. Stattdessen opfert es Puffer und Caches des Dateisystems. Auf MacOS X wird durch den Verzicht auf diesen Puffer das System angehalten, bis es vollständig unbrauchbar ist. Aber glücklicherweise können wir das unter * msync (... MS_INVALIDATE) * verhindern. Unter Linux scheint es das Verhalten zu sein, das Sie bei madvice beobachtet haben, das verhindert, dass das System abstürzt. – Dave

+1

@Dave: Beachten Sie, dass es keinen Sinn hat, diese Seiten vorzeitig zu löschen. Linux opfert keine Caches und Puffer, sondern tut genau das. Wenn Sie mehr Daten von der Festplatte lesen, muss Linux diese sowieso in den Speicher bringen. Es speichert die Daten, die von der Festplatte gelesen wurden, aber speichert sie nicht als "Cache", sondern als Teil des RSS-Teils des Prozesses, der diese Datei zugeordnet hat. Wenn Linux erneut zwischengespeichert werden muss, werden die dieser Anwendung zugewiesenen Seiten freigegeben. Sie brauchen sich darum nicht zu kümmern! – Juliano

+0

@Juliano: Beachten Sie, dass MADV_SEQUENTIAL dem System ausdrücklich mitteilt, dass auf Seiten nur durch einmaliges sequentielles Lesen zugegriffen wird. Diese Seiten sind perfekte Kandidaten für die Rückforderung.Stattdessen sehe ich, dass auf meiner Box, bis 50% des Speichers (32 GB in diesem Fall) erreicht ist, der Dateicache zurückgewonnen wird. Und ich sehe, dass die Leistung anderer Prozesse sich verschlechtert, Jetzt habe ich einen ridiculus Weg gefunden, Linux zu zwingen, das nicht zu tun. Durch erneutes Mappen und Mappen der Datei, alle 1 GB oder so. Das * löst * das Problem und danach sehe ich keinen Leistungsabfall für andere Prozesse. –