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
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.
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
Original von Golo
Original von MagicAndre1981
GC.Collect();
Das muss - damit es sicher funktioniert - aber zwei Mal hintereinander aufgerufen werden.
Warum den das eigentlich??
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
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
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
Hallo digi333,
geht ja immer noch darum, den Speicherverbrauch zu verhindern ==> zusammengefügt.
herbivore
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
Wie gesagt habe ich Probleme mit dem new... ob so oder so. Der Speicher rennt trotzdem ins unermäßliche. X(
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
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).
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
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???
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
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
Tatsächlich? Hätte ich nicht gedacht...
Weeks of programming can save you hours of planning
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.
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
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
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
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.
Ich würde jetzt mal behaupten, dass dir ohne Code nicht zu helfen ist...
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.
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?? 🤔
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