2012-04-24 6 views
12

Ich schreibe ein Programm, das riesige Datenmengen (in Stücken unterschiedlicher Größe) aus dem Netzwerk empfängt, verarbeitet und in den Speicher schreibt. Da einige Daten sehr groß sein können, begrenzt mein aktueller Ansatz die verwendete Puffergröße. Wenn ein Stück größer ist als die maximale Puffergröße, schreibe ich die Daten in eine temporäre Datei und lese später die Datei in Stücke zur Verarbeitung und dauerhaften Speicherung.mmap und Speichernutzung

Ich frage mich, ob dies verbessert werden kann. Ich lese seit einiger Zeit über mmap, aber ich bin nicht hundertprozentig sicher, ob es mir helfen kann. Meine Idee ist es, mmap zum Lesen der temporären Datei zu verwenden. Hilft das irgendwie? Die Hauptsache, um die es mir geht, ist, dass ein gelegentliches großes Stück Daten meinen Hauptspeicher nicht füllen sollte, wodurch alles andere ausgelagert wird.

Denken Sie auch, dass der Ansatz mit temporären Dateien nützlich ist? Sollte ich das überhaupt tun oder sollte ich dem Linux-Speichermanager vertrauen, dass er den Job für mich erledigt? Oder sollte ich etwas ganz anderes machen?

+0

Wie groß ist 'groß'? Am wichtigsten ist, wie vergleicht es sich mit dem gesamten realen RAM auf dem Computer, wo dies laufen wird? – zwol

+0

Big ist mehrere Gigabyte. Ich habe 24G RAM, so dass einige Dateien so viel wie ein Viertel des physischen RAM oder sogar mehr belegen können. – Elektito

+1

Mit 'mmap()' verursachen Sie im Grunde, dass der Speicher durch eine Datei gesichert wird, anstatt durch Swap gesichert zu werden (sogenannter anonymer Speicher). Unter dem Druck des Speichers kann der Kernel beschließen, dateiunterstützten Speicher aggressiver als anonymer Speicher zurückzufordern, oder er kann das Gegenteil tun, ich weiß es nicht. – ninjalj

Antwort

10

Mmap können Sie in gewisser Weise helfen, ich mit einigen hypothetischen Beispiele erläutern werde:

Das erste, was: Lassen Sie uns sagen, dass Sie nicht genügend Arbeitsspeicher laufen lassen, und Ihre Anwendung, die eine 100MB Batzen malloc'ed haben Speicher 50% davon ausgelagert, das bedeutet, dass das OS 50MB in die Auslagerungsdatei schreiben musste, und wenn Sie es zurücklesen müssen, haben Sie 50MB Ihrer Auslagerungsdatei geschrieben, belegt und dann wieder eingelesen.

Wenn der Speicher nur mmapiert wurde, wird das Betriebssystem diese Information nicht in die Auslagerungsdatei schreiben (da es weiß, dass diese Daten mit der Datei identisch sind), stattdessen werden nur 50MB gelöscht Information (wiederum: Angenommen du hast noch nichts geschrieben) und das war's. Wenn Sie diesen Speicher zum erneuten Lesen benötigen, holt das Betriebssystem den Inhalt nicht aus der Auslagerungsdatei, sondern aus der ursprünglichen Datei, die Sie mma- piert haben. Wenn also ein anderes Programm 50 MB Auslagerung benötigt, sind diese verfügbar. Außerdem gibt es keinen Overhead mit Swapfile-Manipulation.

Nehmen wir an, Sie lesen einen 100MB Datenblock, und entsprechend den ersten 1MB Headerdaten befindet sich die gewünschte Information bei Offset 75MB, Sie brauchen also nichts zwischen 1 ~ 74.9MB! Sie haben es nur gelesen, um Ihren Code zu vereinfachen. Mit mmap werden Sie nur die Daten lesen, auf die Sie tatsächlich zugegriffen haben (abgerundete 4 KB, oder die OS-Seitengröße, die meistens 4 KB beträgt), sodass nur das erste und das 75. MB gelesen werden. Ich denke, es ist sehr schwierig, einen einfacheren und effektiveren Weg zu finden, Disk-Lesen zu vermeiden als mmap-Dateien. Und wenn Sie aus irgendeinem Grund die Daten bei Offset 37MB benötigen, können Sie es einfach verwenden! Sie müssen es nicht erneut mappen, da die gesamte Datei im Speicher verfügbar ist (natürlich begrenzt durch den Speicherplatz Ihres Prozesses).

Alle gemappten Dateien werden von sich selbst gesichert, nicht von der Auslagerungsdatei. Die Auslagerungsdatei wird erstellt, um Daten zu gewähren, die keine zu sichernde Datei haben. Dies sind normalerweise Daten mallokkiert oder Daten, die gesichert werden durch eine Datei, aber es wurde geändert und [kann/soll nicht] zurückgeschrieben werden, bevor das Programm dem Betriebssystem tatsächlich sagt, dies über einen msync-Aufruf zu tun.

Beachten Sie, dass Sie nicht die gesamte Datei im Speicher abbilden müssen, Sie können jede Menge (2. arg ist "size_t length") ab einer beliebigen Stelle abbilden (6. arg - "off_t offset"), aber es sei denn Ihre Datei ist wahrscheinlich enorm, Sie können sicher 1 GB Daten ohne Angst zuordnen, auch wenn das System nur 64 MB physischen Speicher packt, aber das ist zum Lesen, wenn Sie planen zu schreiben, dann sollten Sie konservativer sein und nur die Karte Sachen, die du brauchst.

Mapping-Dateien helfen Ihnen, Ihren Code einfacher zu machen (Sie haben bereits den Dateiinhalt im Speicher, gebrauchsfertig, mit viel weniger Overhead, da es kein anonymer Speicher ist) und schneller (Sie werden nur die Daten lesen, die Sie benötigen) Programm zugegriffen).

+0

Danke. Es ist gut, all das zu wissen, aber leider gilt das meiste nicht für meine derzeitige Situation. – Elektito

3

Der Hauptvorteil von mmap mit großen Dateien besteht darin, die gleiche Speicherzuordnung zwischen zwei oder mehr Dateien zu teilen: Wenn Sie mit MAP_SHARED mmapieren, wird es nur einmal für alle Prozesse in den Speicher geladen, die die Daten mit verwenden Speicher sparen.

Aber AFAIK, mmap bildet die gesamte Datei in den Speicher ab (Here Sie können Beispiele dafür finden, wie mmap mit Dateien größer als physischer Speicher + Auslagerungsspeicher fehlschlägt.) Wenn Sie also auf die Datei von einem einzigen Prozess zugreifen, wird es nicht helfen Sie mit dem physischen Speicherverbrauch.

+0

Gibt es also eine andere Möglichkeit, dass ich sicherstellen kann, dass nicht alle Dateien in den Speicher geladen werden? Sie sehen, ich habe auch ein anderes Problem. Ich muss die Daten für die Speicherung in MongoDB senden. Nun Mongo braucht ich einen Zeiger auf einige In-Memory-Puffer und so scheint es, dass, ob ich die Datei selbst laden oder mmap verwenden, wird die Datei im Speicher in seiner Gesamtheit für einen Zeitraum gespeichert werden. – Elektito

+2

Ich bin nicht vertraut mit MongoDB, aber wenn es einen In-Memory-Puffer, der die gesamte Datei enthält, will, dann scheint es mir keinen Sinn, temporäre Dateien überhaupt zu verwenden. Wenn das Verhalten, wenn Sie direkt aus dem Netzwerk in Speicherpuffer lesen und diese dann an MongoDB weitergeben, inakzeptabel ist, müssen Sie Ihre großen Dateien in Blöcke * innerhalb der Datenbank * zerlegen. – zwol

+0

mmap täuscht tatsächlich "die gesamte Datei in den Speicher", aber es liest es nicht von der Festplatte in den Speicher *, um dies zu tun. Das Mapping von Dateien größer als physischer Speicher + Auslagerungsbereich kann nur fehlschlagen, wenn Sie angegebene Flags oder sehr spezifische Kernel-Konfigurationen verwenden (die nicht häufig verwendet werden) oder wenn Sie versuchen, Dateien mit einer Gesamtgröße größer als Ihr * virtueller * Speicher zu mappen. Die Erschöpfung des virtuellen Speichers ist die eigentliche Bedrohung für 32-Bit-Systeme, aber alles andere sollte nicht dazu führen, dass mmap ausfällt, wenn Sie es richtig machen. – user1643723

1

Ich glaube, dass mmap nicht alle Daten im selben Moment im Speicher benötigt - es verwendet den Seitencache, um zuletzt verwendete Seiten im Speicher zu behalten, und den Rest auf der Festplatte.

Wenn Sie nur einen Chunk nach dem anderen lesen, wird Ihnen die Verwendung einer temporären Datei wahrscheinlich nicht helfen, aber wenn Sie mehrere Chunks gleichzeitig mit mehreren Threads, Prozessen oder mit select/poll lesen, könnte dies passieren.