POSIX-Umgebungen bieten mindestens zwei Möglichkeiten für den Zugriff auf Dateien. Es gibt die Standard - Systemaufrufe open()
, read()
, write()
, und Freunde, aber es gibt auch die Möglichkeit der Verwendung mmap()
der Datei in den virtuellen Speicher abzubilden.
Wann ist es vorzuziehen, eine über die andere zu verwenden? Was sind ihre individuellen Vorteile, die zwei Schnittstellen verdienen?
Antworten:
mmap
ist großartig, wenn mehrere Prozesse schreibgeschützt auf Daten aus derselben Datei zugreifen, was bei den von mir geschriebenen Serversystemen üblich ist.mmap
Ermöglicht all diesen Prozessen, dieselben physischen Speicherseiten gemeinsam zu nutzen, wodurch viel Speicherplatz gespart wird.mmap
Außerdem kann das Betriebssystem Paging-Vorgänge optimieren. Betrachten Sie beispielsweise zwei Programme. Programm,A
das eine1MB
Datei in einen Puffer einliest , der mit erstelltmalloc
, und Programm B, dasmmaps
die 1-MB-Datei in den Speicher legt. Wenn das Betriebssystem einen Teil desA
Speichers austauschen muss, muss es den Inhalt des zu austauschenden Puffers schreiben, bevor es den Speicher wiederverwenden kann. In diesemB
Fall können unverändertemmap
Seiten sofort wiederverwendet werden, da das Betriebssystem weiß, wie sie aus der vorhandenen Datei wiederhergestellt werden können, aus der sie stammenmmap
. (Das Betriebssystem kann erkennen, welche Seiten unverändert sind, indem es beschreibbaremmap
Seiten zunächst als schreibgeschützt markiert und Seg-Fehler abfängt , ähnlich wie bei der Strategie "Beim Schreiben kopieren" .)mmap
ist auch nützlich für die Kommunikation zwischen Prozessen . Sie könnenmmap
eine Datei als Lese- / Schreibzugriff in den Prozessen verwenden, die kommunizieren müssen, und dann Synchronisationsprimitive in dermmap'd
Region verwenden (dafür ist dasMAP_HASSEMAPHORE
Flag vorgesehen).Ein
mmap
unangenehmer Ort kann sein, wenn Sie mit sehr großen Dateien auf einem 32-Bit-Computer arbeiten müssen. Dies liegt daranmmap
, dass im Adressraum Ihres Prozesses ein zusammenhängender Adressblock gefunden werden muss, der groß genug ist, um in den gesamten Bereich der zugeordneten Datei zu passen. Dies kann zu einem Problem werden, wenn Ihr Adressraum fragmentiert wird und möglicherweise 2 GB Adressraum frei sind, aber kein einzelner Bereich für eine Dateizuordnung von 1 GB geeignet ist. In diesem Fall müssen Sie die Datei möglicherweise in kleineren Blöcken zuordnen, als Sie möchten, dass sie passt.Eine weitere mögliche Unannehmlichkeit
mmap
als Ersatz für Lesen / Schreiben besteht darin, dass Sie Ihre Zuordnung für Offsets der Seitengröße starten müssen. Wenn Sie nur einige Daten mit OffsetX
abrufen möchten, müssen Sie diesen Offset korrigieren, damit er mit kompatibel istmmap
.Und schließlich, Lesen / Schreiben der einzige Weg sind Sie können mit einigen Arten von Dateien.
mmap
kann nicht für Dinge wie Pipes und Ttys verwendet werden .quelle
MAP_HASSEMAPHORE
ist spezifisch für BSD.Ein Bereich, in dem ich fand, dass mmap () kein Vorteil ist, war das Lesen kleiner Dateien (unter 16 KB). Der Overhead von Seitenfehlern beim Lesen der gesamten Datei war sehr hoch im Vergleich zu nur einem einzigen read () - Systemaufruf. Dies liegt daran, dass der Kernel einen Lesevorgang in Ihrer Zeitscheibe manchmal vollständig zufriedenstellen kann, was bedeutet, dass Ihr Code nicht wegschaltet. Bei einem Seitenfehler schien es wahrscheinlicher, dass ein anderes Programm geplant wird, wodurch der Dateivorgang eine höhere Latenz aufweist.
quelle
malloc
ein Stück Speicher zu erstellen und 1 darausread
zu machen. Dies ermöglicht, dass derselbe Code, der Speicherzuordnungen verarbeitet, malloc'ed verarbeitet.read
Zugriffe höher ist als der Overhead der Manipulation des virtuellen Speichers.mmap
4 KB müssen 4 Einträge in der Seitentabelle aktualisiert werden. Dasread
Kopieren in einen Puffer von 16 KB umfasst jedoch auch das Aktualisieren von 4 Seitentabelleneinträgen, ganz zu schweigen davon, dass die 16 KB in den Benutzer-Adr-Bereich kopiert werden müssen. Könnten Sie also die Unterschiede der Vorgänge in der Seitentabelle erläutern und erläutern, wie teuer sie sindmmap
?mmap
hat den Vorteil, wenn Sie wahlfreien Zugriff auf große Dateien haben. Ein weiterer Vorteil ist, dass Sie mit Speicheroperationen (memcpy, Zeigerarithmetik) darauf zugreifen können, ohne sich um die Pufferung zu kümmern. Normale E / A können bei Verwendung von Puffern manchmal recht schwierig sein, wenn Sie Strukturen haben, die größer als Ihr Puffer sind. Der zu handhabende Code ist oft schwer zu finden, mmap ist im Allgemeinen einfacher. Das heißt, es gibt bestimmte Fallen bei der Arbeit mitmmap
. Wie bereits erwähnt,mmap
ist die Einrichtung recht kostspielig, daher lohnt es sich, sie nur für eine bestimmte Größe (von Maschine zu Maschine unterschiedlich) zu verwenden.Für reine sequentielle Zugriffe auf die Datei ist dies auch nicht immer die bessere Lösung, obwohl ein entsprechender Aufruf
madvise
das Problem mindern kann.Sie müssen mit Ausrichtungsbeschränkungen Ihrer Architektur (SPARC, itanium) vorsichtig sein. Bei Lese- / Schreib-E / A sind die Puffer häufig richtig ausgerichtet und werden beim Dereferenzieren eines gegossenen Zeigers nicht abgefangen.
Sie müssen auch darauf achten, dass Sie nicht außerhalb der Karte zugreifen. Dies kann leicht passieren, wenn Sie Zeichenfolgenfunktionen auf Ihrer Karte verwenden und Ihre Datei am Ende keine \ 0 enthält. Dies funktioniert meistens, wenn Ihre Dateigröße nicht ein Vielfaches der Seitengröße beträgt, da die letzte Seite mit 0 gefüllt ist (der zugeordnete Bereich hat immer die Größe eines Vielfachen Ihrer Seitengröße).
quelle
Neben anderen netten Antworten ein Zitat aus der Linux-Systemprogrammierung von Googles Experte Robert Love:
quelle
Die Speicherzuordnung kann im Vergleich zu herkömmlichen E / A einen enormen Geschwindigkeitsvorteil bieten. Das Betriebssystem kann die Daten aus der Quelldatei lesen, wenn die Seiten in der Speicherzuordnungsdatei berührt werden. Dies funktioniert, indem fehlerhafte Seiten erstellt werden, die vom Betriebssystem erkannt werden, und dann lädt das Betriebssystem die entsprechenden Daten automatisch aus der Datei.
Dies funktioniert genauso wie der Paging-Mechanismus und wird normalerweise für Hochgeschwindigkeits-E / A optimiert, indem Daten zu Seitengrenzen und -größen des Systems (normalerweise 4 KB) gelesen werden - eine Größe, für die die meisten Dateisystem-Caches optimiert sind.
quelle
pread
. Unter Solaris 9 Sparc (V890) ist der Zugriff auf das Pread zwei- bis dreimal langsamer alsmemcpy
auf der MMap. Sie haben jedoch Recht, dass der sequentielle Zugriff nicht unbedingt schneller ist.Ein Vorteil, der noch nicht aufgeführt ist, ist die Möglichkeit
mmap()
, eine schreibgeschützte Zuordnung als saubere Seiten beizubehalten. Wenn man einen Puffer im Adressraum des Prozesses zuweist und dannread()
den Puffer aus einer Datei füllt, sind die diesem Puffer entsprechenden Speicherseiten jetzt verschmutzt, seit sie geschrieben wurden.Schmutzige Seiten können vom Kernel nicht aus dem RAM gelöscht werden. Wenn Swap Space vorhanden ist, können sie zum Swap ausgelagert werden. Dies ist jedoch kostspielig und auf einigen Systemen, z. B. kleinen eingebetteten Geräten mit nur Flash-Speicher, gibt es überhaupt keinen Austausch. In diesem Fall bleibt der Puffer im RAM stecken, bis der Prozess beendet wird, oder gibt ihn möglicherweise mit zurück
madvise()
.Nicht auf
mmap()
Seiten geschrieben sind sauber. Wenn der Kernel RAM benötigt, kann er diese einfach löschen und den RAM verwenden, in dem sich die Seiten befanden. Wenn der Prozess, bei dem das Mapping durchgeführt wurde, erneut darauf zugreift, führt dies zu einem Seitenfehler. Der Kernel lädt die Seiten aus der Datei neu, aus der sie ursprünglich stammen . Genauso wie sie überhaupt besiedelt waren.Dies erfordert nicht mehr als einen Prozess, bei dem die zugeordnete Datei verwendet wird, um von Vorteil zu sein.
quelle
read()
haben die Seiten, auf denen Daten gespeichert werden, keine Beziehung zu der Datei, aus der sie möglicherweise stammen. Sie können also nur ausgeschrieben werden, um den Platz zu tauschen. Wenn eine Datei vorhanden istmmap()ed
und die Zuordnung beschreibbar (im Gegensatz zu schreibgeschützt) und beschrieben ist, hängt dies davon ab, ob die Zuordnung warMAP_SHARED
oder warMAP_PRIVATE
. Eine gemeinsam genutzte Zuordnung kann / muss in die Datei geschrieben werden, eine private jedoch nicht.