[Boost] HashTable (unordered_map) WIRKLICH löschen
-
Hallo,
bei meinem Programm benutze ich die Boost Bibliothek.
Mein Problem ist, dass ich temporär sehr große Hashtables (unordered_map und multimap) erstelle (werden bis zu 1 GB groß).
Diese möchte ich ab einem bestimmten Punkt wieder freigeben.
Mit clear() wird nur die Größe auf 0 gesetzt, der allokierte Speicher wird nicht wieder freigegeben.
Mein Ansatz war dann über einen Pool- Allokator einen Speicherbereich festzulegen, allerdings komme ich an der Stelle nicht weiter.Erstelle ich die Maps mit new und zerstöre sie mit delete ändert sich das Verhalten nicht, der Speicher bleibt belegt.
Also die Frage: Wie bekomme ich den Speicher vom Programm wieder ans OS?
Herzlichen Dank schonmal!!
-
MetalMan schrieb:
Hallo,
bei meinem Programm benutze ich die Boost Bibliothek.
Mein Problem ist, dass ich temporär sehr große Hashtables (unordered_map und multimap) erstelle (werden bis zu 1 GB groß).
Diese möchte ich ab einem bestimmten Punkt wieder freigeben.
Mit clear() wird nur die Größe auf 0 gesetzt, der allokierte Speicher wird nicht wieder freigegeben.
Mein Ansatz war dann über einen Pool- Allokator einen Speicherbereich festzulegen, allerdings komme ich an der Stelle nicht weiter.Erstelle ich die Maps mit new und zerstöre sie mit delete ändert sich das Verhalten nicht, der Speicher bleibt belegt.
Also die Frage: Wie bekomme ich den Speicher vom Programm wieder ans OS?
Herzlichen Dank schonmal!!
Es gibt einen großen Unterschied zwischen Speicherfreigabe und der Rückgabe des freigegebenen Speichers an das OS. Den Speicher freigeben kannst (und musst) nur du, mittels delete, free() oder was auch immer das Pendant zur vorhergehenden Speicheranfordeurng ist.
Die Rückgabe des freigegebenen Speichers ans OS kannst du mit Standard-C++ Mitteln nicht steuern. Im Normalfall sollte sich das OS bei Bedarf den nicht mehr gebrauchten Speicher von den Programmen zurückholen.
Warum willst du den Speicher unbedingt ans OS zurückgeben? Hast du irgendwo festgestellt dass das OS Probleme bekommt, anderen Programmen genügend Speicher zur Verfügung zu stellen?
-
Du kannst es mit dem Swap-Trick probieren. Ich weiß nicht, ob das bei unordered_map genauso funktioniert, wie beim Vector:
vector<int> v; ... vector<int>().swap(v); cout << v.capacity();Gruß,
SP
-
Ich glaube das ist nicht MetalMan's Problem. Wie ich das verstanden habe zerstört er seinen Container ja sogar (was die Resourcen definitiv wieder freigeben sollte). Ich vermute mal pumuckl's Post triffts.
-
Hallo.
Das Programm soll Textdateien, die bis zu 3 GB groß sind, einlesen.
Darin stehen Informationen, aus denen ich verschiedene Objekte baue.Ich glaube ich muss das an der Stelle etwas genauer erklären:
Oberklasse = TileType (speichern SubTileType)
Unterklasse = SubTileType (speichern Hashtables mit Pointer auf Wire, PrimitiveSite, Pip)Viele der Informationen wiederholen sich allerdings, sodass ich eine MultiHashTable (MHT) angelegt habe, in der der Pointer auf das existierende Objekt hinterlegt ist.
Diese MHTs werden in einem "TileType" abgespeichert (es gibt ca 100 verschiedene TileTypen pro Datei).Während des Einlesens wird dann in der MHT nach dem Namen gesucht und bei Vorhandensein der Pointer zurückgegeben, dh kein neues Objekt erstellt.
Der Pointer wird dann in einer HashTable in einem "SubTileType" gespeichert.Das ganze ist etwas schwer zu erklären, hoffe es ist so halbwegs verständlich.
Mein Ansatz ist, dass ich die gleichen Information nicht einzeln in Objekte stecke, da ich dann schnell die 2GB des Threads übersteige.
Mit dem oben genannten Ansatz DACHTE ich, dass ich ohne viel Speicher auskomme, da ich sobald ein Objekt bekannt ist (in der MHT im TileType steht) nur den Pointer in der untergeordneten Klasse SubTileType speicher.Status Quo:
Ich teste nun mit einer kleineren Textdatei (400 MB) und belege nun schon 1,6 GB und bei 2GB ist ja Schluss.
Ich weiß selbst noch nicht, warum soviel Speicher beim Aufbau alloziert wird.
Da ich in den Hashtables allerdings lange Strings als Key ablege, könnte das ein Grund sein,oder?Gruß und Danke für die Hilfe
-
Du hast Recht, ich definiere mir zunächst die HashTables:
typedef boost::unordered_map<std::string, Pip* > hashtablePips;Dann lege ich sie mit new an:
hashtablePips * htPips = new hashtablePips();und am ende zerstöre ich sie:
delete htPips;Gruß
-
Wer ist Besitzer der Pips? Soll heißen: Liegen die Pips irgendwo fest in anderen Containern, oder ist deine hashtable die enizige, die Zeiger darauf hält? Im letzten Fall musst du natürlich zusehen, dass du für die Pips auch delete aufrufst und deren Speicher freigibst, das geschieht nicht automatisch. Im ersten Fall musst du drauf achten, dass du keine dangling pointer in deinen hashtables hast, also z.B. die Pips selber aus dem anderen Container löscht und die Pointer darauf in der hashtable lässt, wo sie dann ins Nirvana zeigen.
-
Die Pips existieren nur als Objekt (Pointer) und werden in der MHT in dem TileType und in den HTs mehrerer SubTileTypes abgespeichert.
Die MHTs in den TileTypes brauche ich daher nur, bis ich mit einlesen fertig bin.
Danach will ich nur die MHT löschen, die Pointer dürfen dann nich gelöscht werden, sonst existieren die Objekte ja in den HT der SubTileTypes nicht mehr.Habe auch schon überlegt, ob ich SmartPointer von Boost nehmen sollte (Referenzzähler) aber so sollte es ja auch gehen.
-
Eine Verständnisfrage: Womit misst du den Speicher, der von deiner Applikation belegt wurde? Geht es dir darum, daß der Speicher deiner Applikation nach dem delete immer noch eine ähnliche Größenordnung hat wie vor dem Delete ( z.B. weil das so im Taskmanager angezeigt wird) ? Wenn ja: das liegt an der Speicherverwaltung von Windows, sofern du mit Windows arbeitet. Dort werden die Pages deiner Hashmap in prozessspezifischen Freelisten gehalten, um bei weiteren Mem-Anforderungen cache-günstiger reagieren zu können. Will ein anderer Prozess Speicher haben und es steht nicht ausreichend freier Speicher zur Verfügung, wird dieser von den prozessbezogenen Freelisten abgezogen.
Wenn es sich um etwas anderes handelt: ignoriere einfach meine Äußerungen.
Gruß Kimmi
-
Danke für deine Antwort. Ja, ich beobachte nur mit dem TaskManager.
Das der Speicher nicht freigegeben wird, habe ich auch schon gelesen.
Das Problem ist nur, wie oben beschrieben, dass wenn ich größere Dateien einlese schnell die 2GB Grenze erreicht ist.
Könnte ich den Speicher der temporär, zum Vergleich angelegten SubTileTypes mit dessen Hashtables wieder freigeben, würde der Speicher reichen (so hoffe ich zumindest).
-
MetalMan schrieb:
Danke für deine Antwort.
Das der Speicher nicht freigegeben wird, habe ich auch schon gelesen.
Das Problem ist nur, wie oben beschrieben, dass wenn ich größere Dateien einlese schnell die 2GB Grenze erreicht ist.
Könnte ich den Speicher der temporär, zum Vergleich angelegten SubTileTypes mit dessen Hashtables wieder freigeben, würde der Speicher reichen (so hoffe ich zumindest).Du verstehst scheinbar immer noch nicht ganz, was wir dir hier sagen wollen: Wenn du den Speicher im Code mit delete ordentlich wieder dann ist er auch freigegeben. Dein Betriebssystem zeigt dir trotzdem noch deine 2 GB an, obwohl der Speicher korrekt freigegeben wurde. Du brauchst dir deswegen keine Sorgen zu machen, das Betriebssystem kümmert sich drum, den Speicher anderen Prozessen zur Verfügung zu stellen, sollten sie ihn brauchen.
Voraussetzung ist allerdings, dass du keine Memory-leaks erzeugst, z.B. mit den Dingen, die du in den hashtables speicherst.