bad_alloc Fehler bei Visual Studio 10



  • Hallo,

    Ich habe eine Simulation in C++ geschrieben, die sehr viele Objekte aufeinmal verwalten muss. Momentan handelt es sich dabei um 300x300x300=27 000 000 Objekte a 8 Byte ==> knapp 25mb was heutzutage ja durchaus nicht viel ist.
    Dennoch bekomme ich immer einen Speicherfehler, wenn ich mehr als 11 000 000 Elemente erschaffe.
    Alle Elemente werden auf dem Heap gespeichert und mit einem std::vector verwaltet, im Code sieht das so aus:

    //...
    std::vector<myObject*> saveVector
    //in einer großen Schleife sieht der Aufruf so aus:
    saveVector.push_back(new myObject(..));
    

    Meine erste Idee war, dass der Stack zu klein wird für saveVector, also habe ich folgendes gemacht:

    //...
    std::vector<myObject*> *saveVector;
    //diesen Aufruf scheint es nur bei visual studio zu geben, funkt aber. size=27 000 000
    saveVector = new std::vector<myObject*>(size);
    //in einer großen Schleife sieht der Aufruf so aus:
    saveVector->push_back(new myObject(..));
    

    Dennoch schmeißt Visual Studio mir weiterhin einen Fehler bei ca. 11 000 000 Objekten. Fehlermledung ist:

    Microsoft C++ exception: std::bad_alloc at memory location 0x003cf96c..

    Muss ich eine Einstellung in Visual Studio ändern oder habe ich irgendwo falsch gedacht?
    Der Code funkt für kleiner Größen problemlos (schmeißt ja auch erst bei 11 000 000 den Fehler). Die Objektgrößen passen auch, habs mit sizeof getestet.



  • Zeig mal den Code von myObject.



  • Erstens ist deine Rechnung falsch, 27 Millionen mal 8 ist 216 Millionen, also ca. 206 MB. Zweitens allozierst du die einzeln vom Heap, es kommt also pro Objekt noch einiges an Verwaltungsoverhead dazu, ich schätze mal 8 Byte pro Objekt, damit sind wir schon bei 412 MB. Der Vektor enthält pro Objekt einen Zeiger von (nehm ich mal an) 4 Bytes, macht nochmals 103 MB, insgesamt 515 MB. Das ist zwar immer noch nicht sooo viel, aber wer weiß...

    Vielleicht kannst du die Objekte direkt in den Vektor packen statt sie einzeln zu allozieren? Ansonsten kannst du über einen eigenen Allokator nachdenken.

    Meine erste Idee war, dass der Stack zu klein wird für saveVector

    Der Vektor alloziert seinen Inhalt auf dem Heap, das kann also nicht sein. Das vector-Objekt selbst besteht im Grunde nur aus einem Pointer und zwei Größenangaben für Kapazität und Größe.



  • Mal ne rein prinzipielle Frage: Wenn diese Objekte nur so klein sind würde ich mal fast vermuten dass sie evtl. eigentlich Wertsemantik haben könnten? Wenn ja: Warum speicherst du in dem vector nur Pointer auf die Objekte und nicht die Objekte direkt? Das würde nicht nur Speicher sparen sondern wäre vermutlich auch schneller.



  • Ai mit der Rechnung habe ich mit tatsächlich vertan. Ich hab gerade nochmal meine Planungsdateien durchgesehen und da habe ich mich gott sei dank nicht so vertan. Also die prinzipielle Idee sollte funktionieren.
    Dass noch Speicherverbrauch hinzukommt für die Verwaltung hatte ich erwartet, aber so viel ist echt nicht ohne muss ich sagen. Aber gut, die 4GB sollten das hier ja noch fassen 😉

    Die Objekte müssen leider schon Objekte sein. Ich muss eine Position (X/Y/Z) und einige weitere kleinere Daten speichern:

    class myObject {
    //...
    	private:
    		Bit32Position *pos;
    		unsigned short visits;
    		char gasvalue;
    		char blocked_active;
    //...
    
    class Bit32Position {
    	private:
    		int position;
    
    	public:
    		static const int maxXY = 2047; //2^11-1
    		static const int maxZ = 1023; //2^10-1
    

    Die Bit32Position repräsentiert eine Position (X/Y/Z) mit einem integer um Platz zu sparen. Die Adressierung wird dann mit Shiftoperationen gemacht, die auch getestet funktionieren.



  • Ich seh da nichts was gegen einen std::vector<myObject> spricht...



  • Ohje ... die myObject s speichern auch noch Pointer auf Bit32Position ? Werden die vielleicht auch noch einzeln auf dem Heap alloziert? Das macht dann wohl nochmal 412MB (unter denselben Annahmen wie vorhin).



  • Jo, für mich sieht das so aus als sollte man da mal alle unnötigen Indirektionen entfernen. C++ ist nicht Java...



  • Berechne doch einfach mal die Differenz der Adresse des letzten Objekts und des ersten Objekts. Dann haste den real verbrauchten Speicher. Natürlich nur unter der Annahme, dass die Adressen linear alloziiert werden. Sollte aber normalerweise der Fall sein.

    Wenn Du mit Debug-Heap kompilierst, dann kann der real verbrauchte Speicher pro Objekt übrigens wesentlich mehr sein, da noch diverse andere Infos gespeichert werden. Unter anderem auch Füllbytes vor und nach der Allokation um zu Entdecken, ob möglicherweise mal über deren Grenzen hinaus geschrieben wurde.



  • Morle schrieb:

    Berechne doch einfach mal die Differenz der Adresse des letzten Objekts und des ersten Objekts. Dann haste

    eine schöne Hausnummer ausgerechnet.


Anmelden zum Antworten