Problem mit regelmäßigem bad_alloc bei new



  • Hallo,

    erst einmal etwas Code:

    leaf->m_indices = new TVertexIndex[leaf->m_iNumQuads * 4];
    

    Diese Code-Zeile wird rund 17.000 Mal durchlaufen und funktioniert. Ändere ich sie aber um in

    leaf->m_indices = new TVertexIndex[leaf->m_iNumQuads * [b][u]6[/u][/b]];
    

    so wird bei einem bestimmten Durchlauf (immer beim selben) ein bad_alloc geworfen.

    Meine Frage ist nun, woran das liegen kann? Genug Arbeitsspeicher habe ich nämlich noch definitiv, wenn die Ausnahme geworfen wird.

    Vielen Dank im Voraus,
    bin für jeden Hinweis dankbar 🙂



  • the[V]oid schrieb:

    Meine Frage ist nun, woran das liegen kann? Genug Arbeitsspeicher habe ich nämlich noch definitiv, wenn die Ausnahme geworfen wird.

    Wenn es nicht an zuwenig Speicher liegt, liegt es vermutlich an zuwenig Speicher am Stück.

    Machst Du zwischendurch auch mal deletes? 😉



  • Hallo,

    ja, ich mache überall dort deletes, wo es geht, nur ist die Methode, in der diese Codezeile steht, eben dafür gedacht, einen ziemlich dicken Speicherbrocken zu generieren, der erst verarbeitet werden muss und erst dann entladen werden kann.

    Was meinst du mit "zuwenig Speicher am Stück"?
    Wie könnte man probieren, das Problem in den Griff zu kriegen?

    mfG!



  • Mit "am Stück" meine ich, dass wenn Du 500 MB frei hast, das auch 100 verteilte Blöcke a 5 MB sein könnten. Dann bekommst Du zwar noch jede Menge 5 MB Blöcke, aber keinen 50 MB-Block mehr, weil nirgendwo 50 MB am Stück frei sind (Speicherfragmentierung). Wie groß ist denn m_iNumQuads im Schnitt?

    Ansonsten, mal angenommen m_iNumQuads ist 10.000, und Du machst 17.000 Durchläufe, und nirgends ein delete zwischen den Durchläufen, bist Du auch schon über 900 MB insgesamt.


  • Mod

    was steht in m_iNumQuads drin? wie groß (sizeof) ist TVertexIndex? besitzt TVertexIndex einen überladenen operator new[] ? passen alle delete zum new - eckige Klammern irgendwo vergessen?



  • OK, das mit der Speicherfragmentierung verstehe ich. Ich habe auch schon geglaubt, dass das wirklich der Grund des Fehlers ist, zumal leaf->m_iNumQuads ziemlich große Werte annimmt. Beim Versuch, dies zu optimieren, habe ich einen Fehler gefunden, der diesen Wert unnötig vergrößert. Als ich dann versuchte, diesen zu beheben, bin ich in ein sehr ähnliches Problem geraten, das ich mir mit der Speicherfragmentierung aber nicht erklären kann. Ich versuche, es zu beschreiben:

    (alle wirklich relevanten Code-Zeilen sind fett hervorgehoben)

    Erst einmal habe ich die Methode createLeafGeometry(), die rund 17.000 Mal aufgerufen wird:

    void createLeafGeometry(TerrainTileQuadTreeData** leaf_) {
    	[b]*leaf_ = new CTerrainTileQuadTreeData;[/b]
    	TerrainTileQuadTreeData* leaf = *leaf_;
    
    	// ...
    
    	leaf->m_iNumQuads = countQuads(quadTree);
    	leaf->m_indices = new TVertexIndex[leaf->m_iNumQuads * 4];
    
    	// ...
    }
    

    Sie behilft sich der Hilfsmethode countQuads():

    int countQuads(CQuadTree* pQuadTree) {
    	int iLocalIndices = 0;
    	if (pQuadTree->isLeaf()) {
    		iLocalIndices = 1;
    	} else {
    		for (unsigned int iChild = 0; iChild < 4; iChild++) {
    			[b]iLocalIndices += countIndices(pQuadTree->child(iChild));[/b]
    		}
    	}
    	return iLocalIndices;
    }
    

    Hier habe ich nun den bereits erwähnten Fehler entdeckt: statt rekursiv countQuads() in Zeile 7 aufzurufen, findet sich dort der Aufruf von countIndices, die folgendermaßen definiert ist:

    inline int countIndices(CQuadTree* pQuadTree) {
    	[b]return countQuads(pQuadTree) * 4;[/b]
    }
    

    Nun habe ich in der Definition von countQuads in Zeile 7 das countIndices durch countQuads ersetzt. Jetzt wird bereits beim zweiten Aufruf von createLeafGeometry() in Zeile 2 (bei new) ein bad_alloc geworfen, obwohl der Wert von leaf->m_indices im vorherigen Aufruf statt bei 35.000 nurnoch bei 49 lag, im vorausgegangenen Schritt also wesentlich weniger Speicher verbraucht wurde. Mit countIndices statt countQuads, was in einem viel zu hohen Wert für leaf->m_iNumQuads resultiert, wenn also eine Menge Speicher verschwendet wird, hat es ja funktioniert - Deshalb kann ich es mir nicht mit der Speicherfragmentierung erklären.

    Kann mir das jemand erklären? 😞



  • Ist das jetzt ein c&p-Fehler oder fehlt in Zeile 6 der Create-Funktion tatsächlich eine Indirektion? Wenn ja, wundert es mich, daß der Code überhaupt compiliert wird.



  • the[V]oid schrieb:

    Jetzt wird bereits beim zweiten Aufruf von createLeafGeometry() in Zeile 2 (bei new) ein bad_alloc geworfen

    Bist du dir auch sicher, dass der Fehler bei eben genau diesem "new" kommt und nicht evtl aus dem Konstruktor von "CTerrainTileQuadTreeData", dass da vielleicht zuviel Speicher angefordert wird?



  • CStoll schrieb:

    Ist das jetzt ein c&p-Fehler oder fehlt in Zeile 6 der Create-Funktion tatsächlich eine Indirektion?

    Sorry, war ein C&P Fehler! Ist nun verbessert.

    Badestrand schrieb:

    Bist du dir auch sicher, dass der Fehler bei eben genau diesem "new" kommt und nicht evtl aus dem Konstruktor von "CTerrainTileQuadTreeData", dass da vielleicht zuviel Speicher angefordert wird?

    Ja, da bin ich mir sicher. Der Konstruktor von CTerrainTileQuadTreeData ist übrigens leer:

    class CTerrainTileQuadTreeData {
    public:
    	CTerrainTileQuadTreeData() {}
    	// ...
    };
    

  • Mod

    the[V]oid schrieb:

    Der Konstruktor von CTerrainTileQuadTreeData ist übrigens leer:

    Ganz schlecht. Warum macht createLeafGeometry die Arbeit, die der Konstruktor tun sollte? Vielleicht liegts ja schlicht an etwas nicht Initialisiertem.


Anmelden zum Antworten