364 Stimmen

Wann sollte ich mmap für den Dateizugriff verwenden?

POSIX-Umgebungen bieten mindestens zwei Möglichkeiten, auf Dateien zuzugreifen. Es gibt die Standard-Systemaufrufe open() , read() , write() und Freunde, aber es gibt auch die Möglichkeit, mit mmap() um die Datei im virtuellen Speicher abzubilden.

Wann ist es besser, das eine zu verwenden als das andere? Welche individuellen Vorteile sprechen dafür, zwei Schnittstellen einzubeziehen?

372voto

Don Neufeld Punkte 21948

mmap ist großartig, wenn Sie mehrere Prozesse haben, die nur lesend auf Daten aus derselben Datei zugreifen, was bei der Art von Serversystemen, die ich schreibe, üblich ist. mmap ermöglicht es all diesen Prozessen, sich dieselben physischen Speicherseiten zu teilen, was eine Menge Speicherplatz spart.

mmap ermöglicht es dem Betriebssystem auch, Auslagerungsvorgänge zu optimieren. Nehmen wir zum Beispiel zwei Programme: Programm A die in einem 1MB Datei in einen Puffer, der mit malloc und das Programm B, das mmaps die 1-MB-Datei in den Speicher. Wenn das Betriebssystem einen Teil der Datei auslagern muss A Wenn das Programm den Speicher verlässt, muss es den Inhalt des Puffers in den Swap-Bereich schreiben, bevor es den Speicher wieder verwenden kann. In B Fall jede unveränderte mmap d-Seiten können sofort wiederverwendet werden, da das Betriebssystem weiß, wie es sie aus der vorhandenen Datei wiederherstellen kann, in der sie waren. mmap 'd von. (Das Betriebssystem kann erkennen, welche Seiten unmodifiziert sind, indem es zunächst beschreibbare Seiten markiert. mmap 'd-Seiten als schreibgeschützt und fangen Seg-Fehler ähnlich wie Kopieren auf Schreiben Strategie).

mmap ist auch nützlich für prozessübergreifende Kommunikation . Sie können mmap eine Datei als Lese-/Schreibzugriff in den Prozessen, die miteinander kommunizieren müssen, und verwenden Sie dann Synchronisierungsprimitive in der mmap'd Region (das ist das, was die MAP_HASSEMAPHORE Flagge ist für).

Ein Ort mmap Wenn Sie mit sehr großen Dateien auf einem 32-Bit-Rechner arbeiten müssen, kann das unangenehm sein. Dies ist, weil mmap muß einen zusammenhängenden Adreßblock im Adreßraum Ihres Prozesses finden, der groß genug ist, um den gesamten Bereich der abzubildenden Datei aufzunehmen. Dies kann zu einem Problem werden, wenn Ihr Adreßraum fragmentiert ist, d.h. Sie haben vielleicht 2 GB Adreßraum frei, aber kein einzelner Bereich davon paßt für eine 1 GB große Dateiabbildung. In diesem Fall müssen Sie die Datei möglicherweise in kleineren Teilen abbilden, als Sie möchten, damit sie passt.

Eine weitere potenzielle Unannehmlichkeit bei mmap als Ersatz für Lesen/Schreiben ist, dass Sie Ihre Zuordnung auf Offsets der Seitengröße beginnen müssen. Wenn Sie nur einige Daten am Offset abrufen wollen X müssen Sie den Offset so korrigieren, dass er kompatibel ist mit mmap .

Und schließlich sind Lesen und Schreiben die einzige Möglichkeit, die kann mit einigen Dateitypen arbeiten. mmap kann nicht verwendet werden für Dinge wie Rohre y ttys .

82voto

Ben Combee Punkte 16303

Ein Bereich, in dem ich mmap() nicht als vorteilhaft empfand, war beim Lesen kleiner Dateien (unter 16K). Der Overhead des Page Faulting zum Lesen der gesamten Datei war sehr hoch im Vergleich zu einem einzigen read()-Systemaufruf. Das liegt daran, dass der Kernel manchmal einen Lesevorgang vollständig in Ihrer Zeitscheibe abwickeln kann, was bedeutet, dass Ihr Code nicht weggeschaltet wird. Bei einem Page Fault war es wahrscheinlicher, dass ein anderes Programm geplant wurde, wodurch die Dateioperation eine höhere Latenzzeit hatte.

54voto

Patrick Schlüter Punkte 10870

mmap hat den Vorteil, dass man bei großen Dateien einen zufälligen Zugriff hat. Ein weiterer Vorteil ist, dass man mit Speicheroperationen (memcpy, Zeigerarithmetik) darauf zugreifen kann, ohne sich um die Pufferung kümmern zu müssen. Normale E/A kann bei der Verwendung von Puffern manchmal recht schwierig sein, wenn die Strukturen größer als der Puffer sind. Der Code, um das zu handhaben, ist oft schwer zu bewerkstelligen, mmap ist im Allgemeinen einfacher. Dennoch gibt es bestimmte Fallen bei der Arbeit mit mmap . Wie bereits erwähnt wurde, mmap ist in der Einrichtung recht kostspielig und lohnt sich daher nur für eine bestimmte Größe (die von Maschine zu Maschine variiert).

Bei rein sequentiellen Zugriffen auf die Datei ist es auch nicht immer die bessere Lösung, obwohl ein entsprechender Aufruf von madvise kann das Problem entschärfen.

Sie müssen mit Ausrichtungsbeschränkungen Ihrer Architektur (SPARC, Itanium) vorsichtig sein, mit Lesen/Schreiben IO die Puffer sind oft richtig ausgerichtet und nicht Trap bei der Dereferenzierung eines gegossenen Zeigers.

Sie müssen auch darauf achten, dass Sie nicht außerhalb der Karte zugreifen. Das kann leicht passieren, wenn Sie String-Funktionen in Ihrer Map verwenden und Ihre Datei keine \0 am Ende. In den meisten Fällen funktioniert es, wenn die Dateigröße kein Vielfaches der Seitengröße ist, da die letzte Seite mit 0 gefüllt ist (der zugeordnete Bereich ist immer ein Vielfaches der Seitengröße).

52voto

Miljen Mikic Punkte 14059

Neben anderen netten Antworten, ein Zitat aus Linux-Systemprogrammierung geschrieben vom Google-Experten Robert Love:

Vorteile von mmap( )

Manipulation von Dateien über mmap( ) hat eine Handvoll Vorteile gegenüber dem Standard read( ) y write( ) Systemaufrufe. Dazu gehören:

  • Das Lesen von und Schreiben in eine Memory-Mapped-Datei vermeidet die überflüssige Kopie, die bei der Verwendung der read( ) o write( ) System Aufrufe, bei denen die Daten in und aus einem User-Space-Puffer kopiert werden müssen.

  • Abgesehen von möglichen Seitenfehlern verursacht das Lesen von und Schreiben in eine speicherabgebildete Datei keinen Systemaufruf oder Kontextwechsel Overhead. Es ist so einfach wie der Zugriff auf den Speicher.

  • Wenn mehrere Prozesse das gleiche Objekt im Speicher abbilden, werden die Daten von allen Prozessen gemeinsam genutzt. Schreibgeschützte und gemeinsam beschreibbare Mappings werden in ihrer Gesamtheit gemeinsam genutzt; private beschreibbare Mappings haben ihre noch-nicht-COW (copy-on-write) Seiten gemeinsam genutzt.

  • Die Umgehung der Abbildung beinhaltet triviale Zeigermanipulationen. Es besteht keine Notwendigkeit für die lseek( ) Systemaufruf.

Aus diesen Gründen, mmap( ) ist eine gute Wahl für viele Anwendungen.

Nachteile von mmap( )

Es gibt einige Punkte, die bei der Verwendung zu beachten sind mmap( ) :

  • Speicherzuordnungen sind immer eine ganzzahlige Anzahl von Seiten groß. Daher ist der Unterschied zwischen der Größe der Sicherungsdatei und einer einer ganzzahligen Anzahl von Seiten als Schlupfspeicher "verschwendet". Bei kleinen Dateien kann ein beträchtlicher Prozentsatz der Abbildung verschwendet werden. Zum Beispiel, mit 4 KB-Seiten verschwendet eine 7-Byte-Zuordnung 4.089 Bytes.

  • Die Speicherzuordnungen müssen in den Adressraum des Prozesses passen. Bei einem 32-Bit-Adressraum kann eine sehr große Anzahl von Mappings unterschiedlicher Größe zu einer Fragmentierung des Adressraums führen, was es schwierig macht große freie zusammenhängende Bereiche zu finden. Dieses Problem ist natürlich bei einem weniger offensichtlich bei einem 64-Bit-Adressraum.

  • Bei der Erstellung und Pflege der Speicherzuordnungen und der zugehörigen Datenstrukturen innerhalb des Kernels entsteht ein Overhead. Dieser Overhead wird im Allgemeinen durch die Beseitigung der im vorigen Abschnitt erwähnten doppelten Kopie Abschnitt erwähnte Doppelkopie, insbesondere bei größeren und häufig genutzten Dateien.

Aus diesen Gründen sind die Vorteile der mmap( ) sind am stärksten verwirklicht wenn die gemappte Datei groß ist (und somit der vergeudete Platz nur einen kleinen Prozentsatz des gesamten Mappings) oder wenn die Gesamtgröße der gemappten Datei gleichmäßig durch die Seitengröße teilbar ist (und somit kein Platz verschwendet wird). Platz).

15voto

Die Speicherzuordnung hat das Potenzial für einen enormen Geschwindigkeitsvorteil im Vergleich zum herkömmlichen IO. Es ermöglicht dem Betriebssystem, die Daten aus der Quelldatei zu lesen, wenn die Seiten in der Memory-Mapping-Datei berührt werden. Dies funktioniert durch die Erstellung von Fehlerseiten, die vom Betriebssystem erkannt werden, und das Betriebssystem lädt dann automatisch die entsprechenden Daten aus der Datei.

Dies funktioniert auf die gleiche Weise wie der Paging-Mechanismus und ist in der Regel für Hochgeschwindigkeits-E/A optimiert, indem Daten an Systemseitengrenzen und -größen (normalerweise 4K) gelesen werden - eine Größe, für die die meisten Dateisystem-Caches optimiert sind.

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