Wie kann man vermeiden in hohen Speicherverbrauch Anwendung aus dem Speicher ausgeführt wird? C / C ++

StackOverflow https://stackoverflow.com/questions/741834

  •  09-09-2019
  •  | 
  •  

Frage

Ich habe einen Konverter geschrieben, die openstreetmap XML-Dateien nimmt und wandelt sie in ein binären Laufzeit-Rendering-Format, das typischerweise etwa 10% der ursprünglichen Größe. Eingabedateigrößen sind in der Regel 3gb und größer. Die Eingabedateien werden nicht in den Speicher auf einmal geladen, sondern gestreamt als Punkte und Polys gesammelt werden, dann ist ein bsp auf ihnen laufen und die Datei ausgegeben. Kürzlich auf größere Dateien läuft es nicht genügend Arbeitsspeicher und stirbt (die in Frage hat 14 Millionen Punkte und 1 Million Polygone). Typischerweise mein Programm wird unter Verwendung von etwa 1 GB bis 1,2 GB RAM, wenn dies geschieht. Ich habe versucht, von 2 bis 8 GB virtuellen Speicher zu erhöhen (auf XP), aber diese Änderung keine Auswirkung hat. Da auch dieser Code Open Source ist, würde ich es gerne habe arbeitet unabhängig vom verfügbaren RAM (wenn auch langsamer), es läuft auf Windows, Linux und Mac.

Welche Techniken kann ich vermeiden verwenden, die es über genügend Arbeitsspeicher ausgeführt? Verarbeiten der Daten in kleinere Teilsätze und dann die endgültigen Ergebnisse verschmelzenden? Mit meiner eigenen virtuellen Speicher Art von Handler? Jede andere Ideen?

War es hilfreich?

Lösung

Zuerst auf einem 32-Bit-System, werden Sie immer auf 4 GB Speicher begrenzt werden, egal Auslagerungsdatei Einstellungen. (Und von denen, werden nur 2GB an Ihren Prozess unter Windows zur Verfügung. Unter Linux Sie haben in der Regel um 3 GB verfügbar)

Die erste offensichtliche Lösung ist auf ein 64-Bit-Betriebssystem zu wechseln, und kompilieren Sie Ihre Anwendung für 64-Bit. Das gibt Ihnen einen sehr großen Raum virtuellen Speicher zu verwenden, und das Betriebssystem werden die Daten tauschen in die und aus der Auslagerungsdatei als notwendigen Dinge weiter zu arbeiten.

Zweitens, Aufteilung kleinere Stücke des Speichers zu einer Zeit kann helfen. Es ist oft einfacher, 4 256MB Stücke freien Speichers als ein 1 GB chunk zu finden.

Drittens teilte das Problem auf. Sie nicht den gesamten Datensatz auf einmal verarbeiten, sondern nur versuchen, zu laden und verarbeiten einen kleinen Abschnitt auf einmal.

Andere Tipps

Haben Sie geprüft, um sicherzustellen Sie nicht Speicher undicht sind überall?

Da Ihr Programm auf Linux tragbar ist, schlage ich es unter Valgrind läuft sicher zu machen.

Es klingt wie Sie bereits eine SAX basierten Ansatz für die XML-Verarbeitung ( Laden der XML, wie Sie statt auf einmal gehen).

Die Lösung ist fast immer um den Algorithmus zu ändern, so dass es das Problem in kleinere Teile schneidet. Körperlich nicht so viel Speicher auf einmal zuweisen, lesen Sie in nur das, was Sie brauchen, zu verarbeiten, dann schreiben Sie es heraus.

Sie können manchmal Speicher erweitern über anstelle der Festplatte, wenn in Ihrem Algorithmus benötigt.

Wenn Sie nicht Ihren Algorithmus aufteilen kann, möchten Sie wahrscheinlich so etwas wie Memory-Mapped-Dateien .

Im schlimmsten Fall können Sie versuchen, etwas zu verwenden, wie VirtualAlloc wenn Sie auf einem Windows-System sind. Wenn Sie auf einem 32-Bit-System sind, können Sie versuchen, etwas zu verwenden, wie Physical Address Extension (PAE) .

Sie könnten auch Eingabe Einschränkungen für Ihr Programm setzen betrachten, und eine andere für 32-Bit- und 64-Bit-Systemen mit.

Ich vermute, Ihre Speicherprobleme sind von der Einhaltung des BSP Baum im Speicher. So halten Sie die BSP auf der Festplatte und hält nur ein paar Brocken im Speicher. Dies sollte ziemlich einfach mit BSP, da die Struktur selbst mehr verleiht als andere Baumstrukturen und die Logik sollte einfach sein. Um effizient und Speicher freundlich Sie einen Cache w / Dirty-Flag, mit dem Cache-Größe auf den verfügbaren Speicher weniger etwas für Luft zum Atmen eingestellt haben.

Auf 32-Bit-XP Ihres maximaler Programm-Adressraum ist 2 GB. Dann haben Sie die Fragmentierung aufgrund DLL und Treiber in Ihrem Adressraum geladen werden. Schließlich haben Sie das Problem der Heap-Fragmentierungs.

Ihre beste Zug ist es einfach mit sich zu bringen, und führen Sie als 64-Bit-Prozess (auf einem 64-Bit-System). Plötzlich all diese Probleme verschwinden. Sie können einen besseren Haufen verwenden Heapfragmentierung Auswirkungen zu mildern, und Sie können versuchen VirtualAlloc mit Ihrem Speicher in einem großen zusammenhängenden Klumpen greifen (und dann bekommen Sie es von dort zu verwalten!) DLL / Fahrer davon abhalten, es fragmentieren.

Schließlich können Sie Ihre BSP über Prozesse aufgeteilt. Komplizierte und schmerzhaft, und setzen ehrlich gesagt es nur auf der Festplatte wäre einfacher, aber in der Theorie könnte man eine bessere Leistung erhalten, indem eine Gruppe von Prozessen den Austausch von Informationen mit, wenn Sie alles resident halten kann (und vorausgesetzt, Sie als Speicher schlauer sein kann als die OS kann Dateipuffer-Griff ... die einen großen if) ist. Jeder Prozess würde wesentlich weniger Speicher benötigen und daher nicht auf die 2 GB Adressraum Limit laufen in sollte. Natürlich können Sie durch RAM brennen werden / viel schneller tauschen.

Sie können die Auswirkungen der Fragmentierung des Adressraums verringern, indem kleinere Stücke zuordnet. Dies wird andere unangenehme Nebenwirkungen haben, aber man konnte eine Backoff-Politik folgen, wo Sie immer kleinere Stücke von Speicher packen, wenn Sie erfolgreich zuordnen scheitern. Häufig dieser einfache Ansatz finden Sie ein Programm, das funktioniert, wenn es sonst der Fall wäre es nicht, aber der Rest der Zeit führt und es könnte.

Boy, nicht 64-Bit-Computing gerade klingt so viel schöner als die anderen Optionen?

Wie werden die Zuweisung Sie Speicher für Punkte? Sind die Zuweisung Sie Punkt einer nach dem anderen (z pt = new Point). Dann abhängig von der Größe des Punktes, können einige Speicher verschwendet bekommen. Zum Beispiel auf Windows-Speicher in den Vielfachen von 16 Bytes zugeordnet, so dass selbst wenn Sie versuchen, fragen 1 Byte zuzuweisen, OS tatsächlich 16 Byte zuzuweisen.

Wenn dies der Fall ist, einen Speicherzuordner mit helfen kann. Sie können eine schnelle Überprüfung mit STL Allocator tun. (Über den neuen Betreiber für die Point-Klasse laden und das STL Allocator verwenden Speicher anstatt ‚malloc‘ zuzuordnen oder neue Betreiber Standard).

Sie können nicht seine Aufteilung und Aufheben der Zuordnung von Speichern in optimaler Weise. Wie andere haben darauf hingewiesen, dass Sie Speicher undicht sein und zu wissen es nicht. Debuggen und Optimieren von Speicherzuweisung wird einige Zeit dauern.

Wenn Sie keine Zeit hat die Optimierung der Speichernutzung verbringen wollen, warum nicht versuchen, die Conservative Garbage Collector ? Es ist ein Plug-in-Ersatz für malloc () / neu und frei (). In der Tat frei () ist eine no-op, so dass Sie nur die Anrufe aus dem Programm entfernen. Wenn stattdessen von Hand optimieren Sie Ihr Programm und einen Pool von Speichern verwalten, wie zuvor vorgeschlagen, werden Sie eine Menge Arbeit am Ende zu tun, dass die CGC bereits für Sie erledigt.

Sie benötigen eine Ausgabe sowie Ihre Eingabe streamen. Wenn Ihr Ausgabeformat nicht streamen-orientiert ist, betrachten zweiten Durchgang zu tun. Wenn zum Beispiel der Ausgabedatei mit Checksumme beginnt / Größe der Daten, lassen Sie Platz auf dem ersten Durchgang und suchen / schreiben zu, dass der Raum später.

Es klingt wie Sie binäre Gespräch txt tun so, warum tun Sie die gesamten Daten im Speicher haben brauchen ?.
Kann nicht lesen Sie nur eine primitive aus txt (xml) dann zu Binary speichern?

Wenn Sie speicher Größe unabhängig sein wollen, müssen Sie eine Größe unabhängigen Algorithmus. Egal, welche Größe Ihr RAM ist, wenn Sie nicht über die Speichernutzung unter Kontrolle haben, Sie gehen in die Grenze stoßen.

Werfen Sie einen Blick auf die am wenigsten Stück Informationen, die Sie möglicherweise ein wenig Ausgabe zu erzeugen, verwenden können. Dann denken Sie an einen Weg, um die Eingabe in Stücke dieser Größe zu unterteilen.

Nun, das klingt einfach, nicht wahr? (Gut, dass ich muss es nicht tun :))

Sie müssen nicht auf 64-Bit-Maschinen wechseln, noch müssen Sie die meisten der 1000 Dinge von anderen vorgeschlagen. Was Sie brauchen, ist ein nachdenklicher Algorithmus.

Hier sind einige Dinge, die Sie tun können, um mit dieser Situation zu helfen:

  • Wenn Sie unter Windows sind, verwenden Datei-Karten ( Beispielcode ). Dies wird über einen einzigen Pufferzeiger Zugriff auf die Datei geben, als ob Sie die gesamte Datei in dem Speicher lesen, nur ohne das wirklich zu tun. Neuere Versionen von Linux Kernel haben einen ähnlichen Mechanismus.
  • Wenn Sie können, und es sieht aus wie könnten Sie die Datei nacheinander scannen und vermeiden, dass ein In-Memory-DOM zu schaffen. Dies wird Ihre Last-Zeit sowie der Speicherbedarf erheblich verringern.
  • Verwenden Sie Pooled-Speicher! Sie werden wahrscheinlich viele kleine Objekte, wie Knoten, Punkte und so weiter haben. Verwenden Sie einen gepoolten Speicher, um zu helfen (ich nehme an, Sie eine nicht verwaltete Sprache verwenden. Suche nach Pooled Zuordnung und Speicherpools).
  • Wenn Sie eine verwaltete Sprache verwenden, zumindest bewegt diesen besonderen Teil in eine nicht verwalteten Sprache und die Kontrolle über den Speicher und Datei lesen. Managed Sprachen haben einen nicht-trivialen Aufwand sowohl in Speicherbedarf und Performance. (Ja, ich weiß, das ist mit "C ++" ...)
  • versucht, einen In-Place zu entwerfen, in dem Sie nur lesen und verarbeiten die minimale Menge an Daten zu einer Zeit, so dass Ihre Speicheranforderungen würden nach unten gehen.

Lassen Sie mich abschließend darauf hin, dass komplexe Aufgaben komplexe Maßnahmen erfordern. Wenn Sie denken, können Sie eine 64-Bit-Rechner mit 8 GB RAM leisten, dann benutzen Sie einfach „Datei in den Speicher lesen, Prozessdaten, schreiben Ausgang“ Algorithmus, auch wenn es einen Tag dauert zu beenden.

gibt es eine gute Technik für das, ist es, einige Instanzen in Dateien zu speichern und sie nach dem Aufstehen, wenn Sie brauchen, um sie zu verwenden.

Diese Technik, die von vielen Open-Source-Software wie Doxygen verwendet wird, skalierbar zu sein, wenn eine große Menge an Speicher benötigt wird.

Dies ist eine alte Frage, aber, da ich vor kurzem das gleiche getan habe ....

Es gibt keine einfache Antwort. In einer idealen Welt würden Sie eine Maschine mit großen Adressraum (dh 64 Bit), und große Mengen an physischen Speicher. Sehr großer Adressraum ist allein nicht ausreichend, oder es wird nur dreschen. In diesem Fall analysiert, um die XML-Datei in eine Datenbank, und mit entsprechenden Anfragen, herausziehen, was Sie brauchen. Sehr wahrscheinlich das ist, was OSM selbst tut (ich glaube, die Welt über 330GB ist).

In der Realität Ich bin immer noch mit XP 32bit aus Zweckmäßigkeitsgründen.

Es ist ein Kompromiss zwischen Raum und Geschwindigkeit. Sie können in jeder beliebigen Menge an Speicher so ziemlich alles tun, vorausgesetzt, Sie mich nicht, wie lange es dauert. Mit STL Strukturen Sie alles analysieren können Sie wollen, aber Sie werden bald über genügend Arbeitsspeicher ausgeführt werden. Sie können Ihre eigenen Verteilern definieren, die tauschen, aber wieder, es ineffizient sein werden, weil die Karten, Vektoren, Sätze usw. nicht wirklich wissen, was Sie tun.

Die einzige Art, wie ich sie alle Arbeiten in einem kleinen Abdruck auf einer 32-Bit-Maschine zu machen, fand, war sehr sorgfältig darüber nachdenken, was ich tat und was nötig war, wann und bricht die Aufgabe, in Stücke schneiden. Speicher effizient verwendet (nie mehr als ~ 100 MB), aber nicht massiv schnell, aber dann spielt es keine Rolle - wie oft man die XML-Daten zu analysieren, hat

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top