Laden...

Garbage collector - Befehl??

Erstellt von digi333 vor 17 Jahren Letzter Beitrag vor 17 Jahren 8.762 Views
D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren
Garbage collector - Befehl??

Ich weiß das die GarbageCollection automatisch läuft, aber ich wollte fragen, ob man den Spiecher per Hand auch noch aufräumen kann. Ich hab ein Programm geschrieben, dass in Videosequenzen Bilder bearbeitet. Am Anfang jedes Frames erzeuge ich ein Bitmap und ein Graphics und zum ende dispose ich es auch wieder. Trotzdem "explodiert" mein Speicher mit 2 bis 3 MB pro Frame. Wenn der Arbeitsspeicher voll ist stürtzt dann die Delphi-Oberfläche ab.

Ich bin ja noch am suchen was da so groß wird, aber jede Idee wäre hilfreich.

Ne Idee?

Gruss
Digi333

906 Beiträge seit 2005
vor 17 Jahren
GC.Collect();
R
494 Beiträge seit 2006
vor 17 Jahren

Wenn du alles per Dispose freigibst sollte der Speicher aber garnicht so voll werden. Bist du sicher, dass du nichts vergessen hast? Evtl mal nen Profiler anwenden.

4.207 Beiträge seit 2003
vor 17 Jahren

Original von MagicAndre1981

GC.Collect();  

Das muss - damit es sicher funktioniert - aber zwei Mal hintereinander aufgerufen werden.

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Original von Golo

Original von MagicAndre1981

GC.Collect();  

Das muss - damit es sicher funktioniert - aber zwei Mal hintereinander aufgerufen werden.

Warum den das eigentlich??

4.207 Beiträge seit 2003
vor 17 Jahren

Weil der Garbage Collector mit Generationen arbeitet ... bei jedem Aufruf von GC.Collect() wird die Generation jedes Objekts erhöht, und erst ab einer gewissen Generation wird das Aufräumen halbwegs "garantiert".

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

5.657 Beiträge seit 2006
vor 17 Jahren

Hi,

du mußt natürlich alle "unmanaged" Ressourcen zu Fuß freigeben, dazu gehören auch die Bitmaps, die bei dir sicher irgendwo im Arbeitsspeicher bleiben. Verwende am besten myBitmapObject.Dispose(), das dürfte dein Problem lösen.

Andererseits wirft der Beitrag die Frage auf, ob es eigentlich sinnvoll ist, den GarbageCollector anzuweisen, an bestimmten Stellen im Programmablauf die Ressourcen freizugeben. Ich hab im Internet die eindeutige Meinung gehört, daß man das nicht tun sollte. Andererseits ist das imho schon sinnvoll, z.B. bei 3D-Anwendungen während die Grafikkarte rechnet und die CPU nix zu tun hat. Aber ich schätze, daß der GC dann schon von selbst drauf kommen würde.

Was haltet ihr davon? Nutzt ihr die Funktionen des GC um die Ressourcen doch wieder von Hand zu verwalten?

Viele Grüße,
Christian

Weeks of programming can save you hours of planning

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren
Bitmapfrage [ich bin anfänger]

Ich hab folgenden Quellcode...


public class beispiel
{
	private Bitmap bmp = null

	public unsafe override void Execute(int width, int height)
	{
		if (bmp != null) // wenn noch altes Bitmap vorhanden, löschen
		{
			bmp.Dispose();
		}
		Bitmap temp = new Bitmap(width, height);
		bmp = new Bitmap(temp);
     temp.Dispose();
		... 		// arbeite mit bmp!
     bmp.Dispose(); // nur zur Sicherheit (wird dann nicht mehr gebraucht)
	}

Ich würde gerne ein Bitmap erzeugen aber ohne new Bitmap. Am liebsten wäre mir es Bitmap bmp global zu besitzen und bei jedem Aufruf wird bmp überschrieben. Leider wird aber erst width und height in der Methode übergeben. Das Problem ist das irgendwie bmp immer neu erzeugt wird durch new und der Speicher irgendwann überquillt. Scheinbar bin ich zu doof für Dispose().

Danke
Digi333

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo digi333,

geht ja immer noch darum, den Speicherverbrauch zu verhindern ==> zusammengefügt.

herbivore

5.657 Beiträge seit 2006
vor 17 Jahren

Ich versteh gar nicht, worauf du hinaus willst. Warum hast du z.B. die Methode als unsafe markiert? Warum gehts nicht so:


public class beispiel
{
    private Bitmap bmp = null;

    public override void Execute(int width, int height)
    {
        if (bmp != null) // wenn noch altes Bitmap vorhanden, löschen
            bmp.Dispose(); // Ungemanagte Ressourcen freigeben
        bmp = new Bitmap(width, height);
    }
}

Die Methode sollte natürlich nur aufgerufen werden, wenn sich die Höhe oder Breite wirklich geändert hat.

Gruß,
Christian

Weeks of programming can save you hours of planning

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Wie gesagt habe ich Probleme mit dem new... ob so oder so. Der Speicher rennt trotzdem ins unermäßliche. X(

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo digi333,

sind denn width und height bei jedem oder zumindest vielen Aufrufen gleich? Dann bräuchtest du die Bitmap ja gar nicht neu zu erzeugen.

herbivore

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Leider ist Bitmap nicht immer gleich groß... sonst hätte ich es ja schon statisch gesetzt. 🙁

Wie gesagt... der Speicher raßt mächtig nach oben. Denn einzigen verdacht den ich hab ist das Bitmap (es existiert zwar noch global ein BitmapData, aber das kann es nicht sein). Der Quelltext ist überschaubar... da kann nichts anderes so schnell wachsen außer ein Bitmap (und das ist das einzige). 🤔

Das unsafe ist hier nur ein Beispiel, da ich in dem richtigen Quellcode noch weitere Übergabeparameter habe (die ich hier nicht angegeben habe).

5.657 Beiträge seit 2006
vor 17 Jahren

Habe ich ja auch schon erwähnt, aber das klärt ja nicht das eigentliche Problem. Du mußt natürlich auch dafür sorgen, daß das Bitmap auch freigegeben wird, wenn die Objekte der "beispiel"-Klasse freigegeben werden. Du mußt das bmp.Dispose() entweder in der beispiel.Dispose() Methode oder im Destructor aufrufen, ansonsten bleibt es im Speicher, auch wenn das beispiel-Objekt vom GC entsorgt wird.

Weeks of programming can save you hours of planning

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Ich sag doch vielleicht bin ich zu doof für Dispose(). Der Originalquelltext ist im grunde wie oben im Beispielquelltext aufgebaut. Erzeuge bmp... Arbeite auf bmp... und "Zerstöre" bmp. Die letzte Zeile in Execute ist bmp.Dispose(). Sind damit nicht die Ressourcen wieder frei???

5.657 Beiträge seit 2006
vor 17 Jahren

Ich sag doch vielleicht bin ich zu doof für Dispose().

Keiner ist zu doof, eine Methode aufzurufen. Es geht darum, sie an der richtigen Stelle aufzurufen. Ich kenne deinen Quelltext nicht, aber ich vermute, wenn du Bitmap.Dispose() im Destructor aufrufst, ist das Problem weg.

Wenn nicht, hilft nur Einzelschritt-Debuggen. Im Taskmanager siehst du, wann deine Anwendung Speicher reserviert und wieder freigibt, bzw. nicht wieder freigibt.

Viele Grüße,
Christian

Weeks of programming can save you hours of planning

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo MrSparkle,

Du mußt das bmp.Dispose() entweder in der beispiel.Dispose() Methode oder im Destructor aufrufen, ansonsten bleibt es im Speicher, auch wenn das beispiel-Objekt vom GC entsorgt wird.

Besser ist natürlich Dispose so früh wie möglich aufzurufen, aber unmanged Speicher einer Bitmap wird natürlich automatisch freigegeben, wenn das Bitmap-Objekt vom GC entsorgt wird.

herbivore

5.657 Beiträge seit 2006
vor 17 Jahren

Tatsächlich? Hätte ich nicht gedacht...

Weeks of programming can save you hours of planning

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Okay... Ich versteh eure Antworten so, dass das Bitmap nicht das Problem ist, da das Dispose() den Speicher wieder frei macht oder sogar im schlimmsten Fall der GC. Das ist schade... da es das Problem leider nicht behebt.

Und die Sache irgendwie umschreiben geht nicht (so dass das new weg ist)?? Den Quelltext kann ich nicht offen legen, aber ich kann versichern, dass da nur kleine Berechnungen drinne sind.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo digi333,

wenn du das Dispose einer Bitmap "vergisst", dann kann es schon sein, dass die Bitmap und deren unverwalteter Speicher eine ganze Weile rumsteht. Aber wenn du kein Dispose vergessen hast, dann liegt es daran wohl nicht. Aber es gib ja noch andere Objekte, die viel Speicher belegen. Wenn diese IDisposable implementieren, dann solltest du auch für die Dispose aufrufen. Es kann aber auch sein, dass du einfach viele Strings mit + zusammenhängt. Das kann auch den Speicher gut voll machen.

herbivore

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Original von herbivore
Es kann aber auch sein, dass du einfach viele Strings mit + zusammenhängt. Das kann auch den Speicher gut voll machen.

Strings??? Ich übergebe Strings an die grafische Oberfläche, aber das ist eigentlich sehr wenig (ich kann mir nicht vorstellen, dass diese 3 Mb groß werden)... Können den Strings tatsächlich so ansteigen? Aber die kann man nicht disposen, oder? Die sollten auf jeden Fall vom GC entfernt werden. Behaupte ich mal...

Gruss
Digi333

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo digi333,

bei dem Zusammenfügen von String geht es nicht um die Größe der Strings, sondern die Vielzahl von temporären Objekten, die in der Summe den Speicher voll machen, bis der GC sie wieder freigibt. Disposen kann man sie nicht.

Der GC sollte ohnehin alle Objekte freigeben, nicht nur Strings. Also auch Bitmaps. Aber eben immer mit einer gewissen Verzögerung.

Reden wir hier wirklich über nur 3MB? Also dann sollten wir das Thema sofort beenden!

herbivore

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Leider nein (hab nochmal nachgeschaut)! Der Code verursacht sogar 10 MB... Das ist fatal, da sekündlich 10 MB dazu kommen. In 30 Sekunden ist mein Arbeitsspeicher voll und die grafische Oberfläche stürzt ab.

B
1.529 Beiträge seit 2006
vor 17 Jahren

Ich würde jetzt mal behaupten, dass dir ohne Code nicht zu helfen ist...

D
386 Beiträge seit 2007
vor 17 Jahren

Und ich behaupte mal tolldreist, dass es IMMER eine sehr dumme Idee ist den Garbage Collector steuern zu wollen. Da geht wohl etwas ganz anderes arg schief..

Pound for pound, plutonium is about as toxic as caffeine when eaten.

D
digi333 Themenstarter:in
290 Beiträge seit 2006
vor 17 Jahren

Ich hab meinen Fehler erkannt und wollte euch natürlich nicht die Antwort vorenthalten. Der Fehler ist zwar trivial, aber für mich unverständlich.

Falsch ist


Bitmap bmp = new Bitmap (width, height);
bmp.Dispose();
//Speicher quillt über

Richtig ist


Bitmap bmp = new Bitmap (width, height, PixelFormat.Format24bppRgb);
bmp.Dispose();
//Speicher quillt nicht über

In der grafischen Oberfläche sieht man keinen Unterschied... halt nur der Speicher. Da ich aber ein absoluter Anfänger bin, würde mich schon der Hintergrund interessieren. Was ist ein Bitmap ohne PixelFormat?? Und was ist dann der jeweilige Defaultwert?? Warum hält der GC den Wert im Speicher?? 🤔

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo digi333,

Default ist PixelFormat.Format32bppArgb. Warum der Unterschied zwischen Format24bppRgb und Format32bppArg für das Überquellen des Speichers verantwortlich sein soll, verstehe ich eben so wenig wie du (24bpp gegenüber 32bpp reduziert den Speicherverbrauch ja lediglich um 1/4). Möglicherweise tatsächlich mal ein Bug im Framework? Unwahrscheinlich, aber nicht ausgeschlossen.

herbivore