Speicher beschränkt nach std::copy?

Cromon

Erfahrenes Mitglied
Hallo zusammen!

Es war relativ schwer einen guten Titel für das Problem zu wählen, mit welchem ich gerade konfrontiert bin, aber ich hoffe, der obige ist für die zukünftig suchenden mit dem gleichen Problem verständlich :).

Ich bin gerade dabei eine Funktion zu schreiben, welche eine Datei abspeichert. Das Format besteht aus Chunks mit Subchunks und so weiter und diese sind somit alle voneinander abhängig. Aus diesem Grund erstelle ich alle Chunks zuerst im Speicher (da die grössten Dateien nicht mehr als 1.5 MB sind nicht weiter ein Problem) und erstelle anschliessend die Verknüpfungen untereinander und speichere sie dann.

Allerdings stehe ich gerade vor einem äusserst merkwürdigen Problem. Nach einer Anweisung im Speichervorgang ist es mir nicht mehr möglich mehr als 367 Bytes über new zu allozieren. Ich kann zwar 367 mal ein Byte allozieren, aber sobald die Summe der Allokationen 367 Bytes überschreitet erhalte ich eine std::bad_alloc-Exception. Dass ich zu wenig freien Speicher habe denke ich kaum, benötigt das Programm an sich lediglich knapp 100 MB Speicher und ist auch das System sonst kaum ausgelastet.

Hier ein bisschen Code zur Verdeutlichung:
Code:
mwid.size = 4 * m_wmids.size();
	if(mwid.size)
	{
		mwid.data = new ui8[mwid.size];
		std::copy(m_wmids.begin(), m_wmids.end(), (ui32*)mwid.data);
	}
// Ab hier kann ich nicht mehr als 367 Bytes allozieren!

Merkwürdig ist jedoch, dass alles glatt läuft, wenn ich nicht std::copy verwende:
Code:
mwid.size = 4 * m_wmids.size();
	if(mwid.size)
	{
		mwid.data = new ui8[mwid.size];
		ui32* tmp = (ui32*)mwid.data;
		for(ui32 i = 0; i < m_wmids.size(); ++i)
			tmp[i] = m_wmids[i];
	}
// Hier kann ich unbeschränkt allozieren

Weiss jemand vielleicht, warum das so ist? Ich würde eigentlich gerne std::copy verwenden, aber bin momentan gezwungen es über die Schleife selbst zu machen.

/Edit:
Zu früh gefreut, es liegt wohl doch nicht an std::copy. Auch in der zweiten Variante ist der Speicher nicht unbeschränkt allozierbar, aber deutlich mehr. NIcht nur 367 Bytes, sondern 2000-3000 Bytes. Ich bin ehrlich gesagt echt ratlos, wie mein System bei solch minimalen Mengen Fehler produzieren kann...

Gruss
Cromon
 
Zuletzt bearbeitet:
Hallo Cromon,

wäre es möglich, dass du das Problem auf ein (kompilierbares) Minimalbeispiel reduzierst? Vielleicht kommst du dabei selber schon auf die Lösung. Und wenn nicht, dann können wir dir zumindest besser bei der Fehlersuche helfen.

Grüße, Matthias
 
Hallo Matthias,

Compilierbar wird schwer, aber ich kann mal die ganze Funktion posten, es wird konkret eh nur diese aufgerufen wenn man auf die p-Taste drückt.

http://pastebin.com/m617f9528

Solltest du noch mehr Angaben benötigen, einfach schreiben :)

Gruss
Cromon
 
Hi.

Du hast vermutlich einfach nur ein Speicherleck, du gibst den angeforderten Speicher nicht wieder frei.

Außerdem speicherst du Zeiger auf lokale Variablen in der Membervariablen m_savechunks.

Und warum gibst du einer lokalen Variablen einen Namen mit dem Präfix m_?

Gruß
 
Hallo deepthroat!

Die Funktion ist noch im Aufbau, die bad_alloc Ausnahme habe ich gesehen als ich kurz testen wollte, ob es bisher funktioniert, daher hat es noch keine deletes drin. Die würden allerdings nichts ändern da es schon beim ersten Aufrufen der Funktion zur Ausnahme kommt.

Das mit dem Vektor ist Absicht, da ich später die Chunks über Nummern ansprechen möchte und nicht über den Name, da das besser funktioniert. Die Zeiger brauche ich nur innerhalb des Gültigkeitsbereiches der lokalen Variabeln, daher ist das auch kein Problem.

Wo habe ich einer lokalen Variabeln m_ gegeben? Die Chunks haben ein m davor, was für "Map" steht, da es sich um Kartendateien handelt.

//Edit:
Ok, stimmt, m_hdr, das ist etwas ungeschickt gewählt, da mhdr bereits vergeben ist, da werde ich mal was ändern :)

//Edit2:
Ich hab jetzt noch etwas weiter mit dem Debugger geforscht. Die Exception wird wirklich wegen "No memory" geworfen. Das kann ich allerdings nicht nachvollziehen. Die Funktion wird nachgewiesenermassen nur einmal aufgerufen. Ich habe sämtliche Variabeln innerhalb der Funktion, die ich für new verwende mir ausgeben lassen, keine ist höher als 50000. Alles in allem alloziere ich vor dem bad_alloc knapp 100 kb Speicher. Des weiteren kann ich vor dem Aufruf der Funktion (also im Handling des Tastedrucks) problemlos 500 mb Speicher allozieren ohne dass eine bad_alloc Exception geworfen wird. Ich verstehe das gerade echt nicht mehr...

Gruss
Cromon
 
Zuletzt bearbeitet:
Compilierbar wird schwer, aber ich kann mal die ganze Funktion posten, es wird konkret eh nur diese aufgerufen wenn man auf die p-Taste drückt.
Ohne ein kompilierbares Minimalbeispiel wird es allerdings für uns schwer, dir irgendwie zu helfen. Allein vom Anschauen des Quellcodes wird vermutlich niemand drauf kommen, zumal kein offensichtlicher Fehler erkennbar ist. Ich mutmaße deshalb, dass der eigentliche Fehler nicht in dieser einen Funktion liegt. Mit der Erstellung eines Minimalbeispiels könntest du aber den Fehler genauer eingrenzen.

Grüße, Matthias
 
Verständlich, allerdings sind alleine in der aktuellen Datei knapp 1000 Zeilen, die schon mindestens nötig sind um überhaupt die nötigen Daten zu bekommen. Ich schau mal, ob ich da was hinbekomme.

Ich denke jedoch schon, dass es in der Funktion etwas sein muss, schliesslich kann ich vor dem Aufruf der Funktion so viel Speicher allozieren wie ich möchte, und innerhalb der Funktion scheitert es sofort.

Gruss
Cromon
 
Hallo deepthroat!

Die Funktion ist noch im Aufbau, die bad_alloc Ausnahme habe ich gesehen als ich kurz testen wollte, ob es bisher funktioniert, daher hat es noch keine deletes drin. Die würden allerdings nichts ändern da es schon beim ersten Aufrufen der Funktion zur Ausnahme kommt.
Dann hast du irgendwo anders schon ein Speicherleck bzw. schon das Speicherlimit ausgeschöpft.

Wieviel virtuellen Speicher benutzt denn das Programm wenn die bad_alloc Ausnahme geworfen wird?
Das mit dem Vektor ist Absicht, da ich später die Chunks über Nummern ansprechen möchte und nicht über den Name, da das besser funktioniert. Die Zeiger brauche ich nur innerhalb des Gültigkeitsbereiches der lokalen Variabeln, daher ist das auch kein Problem.
Warum definierst du dann den Vektor als Membervariable?

Und warum definierst du denn Chunk nicht als Klasse mit ordentlichen Gettern und Settern, oder muss das aus irgendeinem Grund ein POD-Typ sein? Oder hast du Chunk nicht selbst definiert?

Gruß
 
Wo schaue ich den virtuellen Speicher am besten nach? Der Taskmanager gibt mir irgendwie keine vernünftigen Angaben darüber, steht da immer genau die gleiche Zahl.

Der Vektor ist Member der Klasse weil ich zuerst eine andere Überlegung gemacht hatte und er da Member sein musste. Ich könnte Chunk schon noch die entsprechenden Konstrukte geben, werde ich vermutlich sogar mal tun damit der Speicher im Destruktor freigegeben wird.

Das mit dem Speicherlimit glaube ich allerdings weniger.
Code:
ui8* c = new ui8[100000000];
	return;
	std::set<Model*>::iterator itr = m_changed.begin();
	std::set<Model*>::iterator end = m_changed.end();

	for( ; itr != end; ++itr)
		(*itr)->SaveImproved();

	m_changed.clear();

So kann ich das Ganze 14 mal aufrufen bevor eine std::bad_alloc - Exception geworfen wird.

Code:
	std::set<Model*>::iterator itr = m_changed.begin();
	std::set<Model*>::iterator end = m_changed.end();

	for( ; itr != end; ++itr)
		(*itr)->SaveImproved();

	m_changed.clear();

So wird sie schon beim ersten Aufruf geworfen. Daher meine Vermutung, dass der Fehler in der Funktion sein muss.
 
Wo schaue ich den virtuellen Speicher am besten nach? Der Taskmanager gibt mir irgendwie keine vernünftigen Angaben darüber, steht da immer genau die gleiche Zahl.
Hast du auch die Spalte "Größe des virt. Speichers" eingeblendet?

Das mit dem Speicherlimit glaube ich allerdings weniger.
Irgendwo ist der Speicher ja verbraucht worden. Wie oft rufst du denn die Methode auf? Und clearst du irgendwo den m_savechunks Vektor? Wieviel Einträge sind denn da drin?

Ansonsten benutz einfach mal einen Memory-Checker (z.B. valgrind unter Linux oder die Glowcode Evaluierungsversion)

Gruß

PS: Ansonsten schliess ich mich Matthias an. Poste ein Minimalbeispiel.
 
Zuletzt bearbeitet:
Zurück