Die direkte Speicherzuordnung einer Datei vermeidet das Kopieren von Puffern, die bei read()
auftreten und write()
Anrufe. Ruft read()
an und write()
Fügen Sie einen Zeiger auf den Puffer im Adressraum des Prozesses ein, in dem die Daten gespeichert sind. Der Kernel muss die Daten zu/von diesen Speicherorten kopieren. Mit mmap()
ordnet die Datei dem Adressraum des Prozesses zu, sodass der Prozess die Datei direkt adressieren kann und keine Kopien erforderlich sind.
Es gibt auch keinen Overhead für Systemaufrufe, wenn nach dem ersten Aufruf auf eine speicherabgebildete Datei zugegriffen wird, wenn die Datei beim anfänglichen mmap()
in den Speicher geladen wird . Wenn sich eine Seite der zugeordneten Datei nicht im Speicher befindet, generiert der Zugriff einen Fehler und erfordert, dass der Kernel die Seite in den Speicher lädt. Lesen eines großen Blocks mit read()
kann schneller sein als mmap()
in solchen Fällen, wenn mmap()
würde eine erhebliche Anzahl von Fehlern beim Lesen der Datei erzeugen. (Es ist möglich, den Kernel im Voraus mit madvise()
anzukündigen damit der Kernel die Seiten vor dem Zugriff laden kann).
Für weitere Details gibt es eine verwandte Frage zu Stack Overflow:mmap() vs. Leseblöcke
Erstens dominieren bei den meisten IO-Vorgängen die Eigenschaften der zugrunde liegenden Speicherhardware die Leistung. Ein schlecht konfiguriertes RAID5-Array aus neunundzwanzig S-L-O-W-SATA-Festplatten mit 5400 U/min auf einem langsamen, speicherarmen System, das S/W-RAID mit nicht übereinstimmenden Blockgrößen und falsch ausgerichteten Dateisystemen verwendet, wird Ihnen im Vergleich zu einem richtig konfigurierten und ausgerichteten System eine schlechte Leistung liefern SSD RAID 1+0 auf einem Hochleistungscontroller, trotz aller Software-Tunings, die Sie vielleicht versuchen.
Aber nur so mmap()
deutlich schneller sein kann, wenn Sie dieselben Daten mehr als einmal und lesen Die Daten, die Sie lesen, werden aufgrund von Speichermangel zwischen den Lesevorgängen nicht ausgelagert.
Speicherabbildungsschritte:
- Systemaufruf zum Erstellen virtueller Mappings - sehr teuer
- Der Prozess greift zum ersten Mal auf den Speicher zu und verursacht einen Seitenfehler – teuer (und muss möglicherweise wiederholt werden, wenn er ausgelagert wird)
- Der Prozess liest tatsächlich den Speicher
Wenn der Prozess die Schritte 2 und 3 nur einmal für jedes gelesene Datenbit ausführt oder die Daten aufgrund von Speicherdruck aus dem Speicher gelöscht werden, mmap()
wird langsamer sein.
read()
Schritte:
- Der Systemaufruf kopiert Daten von der Festplatte in den Seitencache (kann Seitenfehler verursachen oder nicht, Daten können sich bereits im Seitencache befinden, was dazu führt, dass dies übersprungen wird)
- Daten werden aus dem Seitencache in den Prozessspeicher kopiert (kann Seitenfehler verursachen oder nicht)
Die Speicherzuordnung wird diese Leistung nur aufgrund dieser zusätzlichen Kopie aus dem Seitencache zum Verarbeitungsspeicher übertreffen. Aber eine bloße Kopie einer Speicherseite (oder weniger) muss mehrmals erstellt werden, um die Kosten für die Einrichtung des Mappings zu schlagen - wahrscheinlich. Wie oft hängt von Ihrem System ab. Speicherbandbreite, wie Ihr gesamtes System verwendet wird, alles. Wenn zum Beispiel die Zeit, die die Speicherverwaltung des Kernels zum Erstellen des Mappings benötigt, ohnehin von keinem anderen Prozess verwendet worden wäre, sind die Kosten für das Erstellen des Mappings wirklich nicht sehr hoch. Umgekehrt, wenn Sie viel Verarbeitung auf Ihrem System haben, die eine Menge virtueller Speicherzuordnungserstellung/-zerstörung beinhaltet (d. h. viele kurzlebige Prozesse), kann die Auswirkung von speicherzugeordneter E/A erheblich sein.
Dann gibt es noch read()
mit direktem IO:
- Systemaufruf zum Lesen von der Festplatte in den Prozessspeicherbereich. (kann einen Seitenfehler verursachen oder auch nicht)
Direkte IO-Lesevorgänge sind in Bezug auf die Leistung so gut wie unschlagbar. Aber Sie müssen Ihre IO-Muster wirklich auf Ihre Hardware abstimmen, um die Leistung zu maximieren.
Beachten Sie, dass ein Prozess ziemlich genau kontrollieren kann, ob das Lesen von Daten einen Seitenfehler für den Puffer verursacht, den der Prozess zum Lesen verwendet.
Ist der speicherabgebildete Dateizugriff also schneller? Vielleicht ist es das, vielleicht auch nicht.
Das hängt von Ihrem/Ihren Zugriffsmuster(n) ab. Zusammen mit Ihrer Hardware und allem anderen in Ihren IO-Pfad(en).
Wenn Sie eine 30-GB-Videodatei auf einem Computer mit 4 GB RAM streamen und nie zurückgehen und die Daten erneut lesen, ist das Memory-Mapping der Datei wahrscheinlich das Schlimmste Art, es zu lesen.
Umgekehrt, wenn Sie eine 100-MB-Nachschlagetabelle für einige Daten haben, auf die Sie bei Ihrer Verarbeitung zufällig Milliarden und Abermilliarden Mal zugreifen, und genügend Speicher, damit die Datei niemals ausgelagert wird, wird die Speicherzuordnung alle anderen Zugriffsmethoden zerstören.
Ein großer Vorteil von speicherabgebildeten Dateien
Memory-Mapping-Dateien haben einen großen Vorteil gegenüber anderen Formen von IO:Code-Einfachheit. Es ist wirklich schwer zu übertreffen, wie einfach es ist, auf eine Datei zuzugreifen, als wäre sie im Speicher. Und meistens ist der Leistungsunterschied zwischen dem Memory-Mapping einer Datei und dem Durchführen diskreter IO-Operationen sowieso nicht allzu groß.