Ursachen Memoryleaks in .NET
-
NullBockException schrieb:
das bedeutet? sorry versteh ich nich !
IDisposable da? myObject.Dispose() schreiben.
IDisposable nicht da? Eierschaukeln.
-
Das bedeutet, dass Garbage Collection dich vor Memory Leaks schützt. Und der Preis dafür ist, dass jede andere Art von Ressource praktisch unmöglich zu verwalten wird...
-
Hmm ok verstehe, schön wäre es, wenn der ReSharper mir die Stellen iwürde, an denen ich ein mögliches Dipsose nich aufgerufen habe:)
-
-
Funktioniert offenbar aber nur für lokale Disposable Objekte und die sind kaum ein Problem, weil da kann man using machen und gut ist. Lustig wirds mit Disposable Membern...
-
dot schrieb:
Lustig wirds mit Disposable Membern...
Die sind oft ein guter Hinweis, dass die enthaltende Klasse ebenfalls IDisposable implementieren sollte. In solchen Fällen zieht es sich bis zur Wurzel und ist kein Problem mehr.
-
Ich sehe auch nicht, wieso Member, die man disposen muss, ein Problem darstellen. Dann geht man halt hin und spendiert seiner Klasse selbst Dispose, wo man dann wiederum das Dispose der Member aufruft. Klingt gut. Hab ich was übersehen?
-
Hier scheint ein falsches Verständnis von Dispose vorzuliegen. Unabhängig davon ob man nun using benutzt oder Dispose manuell aufruft ist garantiert das Dispose ausgeführt wird, weil dieses im Finalizer sichergestellt wird. Wurde es vorher nicht manuell aufgerufen wird Dispose spätestens im Finalizer ausgeführt.
Es geht hier allein um den Zeitpunkt wann Disposed werden soll. Auch hat es nur indirekt mit unmanaged Resourcen zu tuen. Relevant ist Dispose für stark begrenzte Resourcen. Klar sind alle Resourcen in einem Computer endlich, aber manche sind halt so stark begrenzt das man sie so schnell wie möglich wieder freigeben will sobald man sie nicht mehr braucht. (z.B. Filehandles, Grafikhandles etc)
Und genau hier steht das Grundprizip der GC im Widerspruch, weil Objekte "irgendwann" abräumt werden. Viele unterliegen der Fehlannahme das eine GC Objekte abräumt wenn die nicht mehr gebraucht werden. Das stimmt aber so nicht. Objekte, die nicht mehr gebraucht werden räumt die GC erst dann ab wenn sie nicht mehr genug Freispeicher hat. Das kann zu einem sehr späten Zeitpunkt passieren.
Gerade für stark begrenzte Resouecen ist das aber sehr schlecht, weil hier für einen beliebigen, unbestimmbaren Zeitraum dann eine Resource gebunden bleibt obwohl sie längst nicht mehr gebraucht würde.
Um dieses Problem zu lösen gibt es das Dispose-Pattern. Mit Dispose() kann der Programmierer den Zeitpunkt bestimmen zu dem die begrenzten Resourcen eines Objekts freigegeben werden. Das Objekt selber wird danach immer noch von der GC abgeräumt zu einem beliebigen, späteren Zeitpunkt.
Natürlich stimmt es also das man Dispose immer aufrufen sollte, aber nicht, weil man sonst ein Resourceleak hätte, sondern weil man sonst eher in Probleme mit begrenzten Resourcen laufen kann.
-
loks schrieb:
Hier scheint ein falsches Verständnis von Dispose vorzuliegen. Unabhängig davon ob man nun using benutzt oder Dispose manuell aufruft ist garantiert das Dispose ausgeführt wird, weil dieses im Finalizer sichergestellt wird. Wurde es vorher nicht manuell aufgerufen wird Dispose spätestens im Finalizer ausgeführt.
Das wusste ich noch nicht, steht das im Standard oder gibts da eine Doku zu? Wuerde das gerne nachlesen.
-
Sprich, der GC ruft die Dispose funktion auf, wenn sie nich schon aufgerufen wurde, allerdings nich deterministisch zu den object/reference scops!?
-
Hab gerade mal hier geschaut:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdfPunkt 17.12 Finalizer. Da hab ich nichts dergleichen gefunden. loks, hast du da andere Quellen?
-
Es stimmt auch imho nicht, dass der vom Compiler generierte Finalizer Dispose automatisch aufruft.
Nur wenn der Entwickler der Klasse den Finalizer gemäß dem Dispose-Pattern korrekt implementiert, greift der Notmechanismus. Aber auch darauf darf man sich nicht verlassen!Warum raucht folgendes nach ein paar hunder Iterationen ab (wobei ich unterstelle, dass der Finalizer von Bitmap korrekt Dispose aufruft)?
for (int i = 0; i < 100000; ++i) { Bitmap b = new Bitmap(@"C:\xxx.bmp"); Console.WriteLine(i); }
Der nicht-verwaltete Speicher (oder eine andere Ressource) geht zur Neige, der GC weiß davon aber nichts, kann die Finalizer nicht triggern wordurch Dispose nicht aufgerufen wird.
-
Firefighter schrieb:
loks schrieb:
Hier scheint ein falsches Verständnis von Dispose vorzuliegen. Unabhängig davon ob man nun using benutzt oder Dispose manuell aufruft ist garantiert das Dispose ausgeführt wird, weil dieses im Finalizer sichergestellt wird. Wurde es vorher nicht manuell aufgerufen wird Dispose spätestens im Finalizer ausgeführt.
Das wusste ich noch nicht, steht das im Standard oder gibts da eine Doku zu? Wuerde das gerne nachlesen.
Nö, steht nicht, weil es nicht stimmt. Aber es gibt ein Pattern, welchem man folgen sollte, wenn man unmanaged Ressourcen verwaltet:
class MyClass : IDisposable { private bool m_isDisposed; ~MyClass() { Dispose(false); } protected virtual void Dispose(bool disposing) { if(!m_isDisposed) { if(disposing) { // auch managed ressourcen freigeben } // unmanaged ressourcen freigeben m_isDisposed = true; } } public void Dispose() { Dispose(true); } }
Edit: http://msdn.microsoft.com/en-us/library/vstudio/b1yfkh5e.aspx
Grüssli
-
@Dravere und µ: Ok, das kam mir naemlich ziemlich merkwuerdig vor. Das Pattern kannte ich ja schon, nur hatte ich mich gewundert das hier automatisch was aufgerufen wird ohne eigenem Zutuen.
-
Ja eben, dachte schon:) Und das Pattern hab ich auch schon verwendet. Aber nun ist mir prinzipell klar, dass Dipsose NICHT vom GC (im Notfall) aufgerufen wird.
Danke Leute, und ihr hab auch was gelernt:)
Grüße
-
Bzgl. des vorgestellten Patterns möchte ich noch sagen, dass man das nur braucht, wenn man tatsächlich unmanaged resources hat. Hat man nur managed resources, braucht man a) keinen Finalizer und b) kein Dispose(bool).
Siehe auch: http://nitoprograms.blogspot.de/2009/08/how-to-implement-idisposable-and.html
-
µ schrieb:
dot schrieb:
Lustig wirds mit Disposable Membern...
Die sind oft ein guter Hinweis, dass die enthaltende Klasse ebenfalls IDisposable implementieren sollte. In solchen Fällen zieht es sich bis zur Wurzel und ist kein Problem mehr.
GPC schrieb:
Ich sehe auch nicht, wieso Member, die man disposen muss, ein Problem darstellen. Dann geht man halt hin und spendiert seiner Klasse selbst Dispose, wo man dann wiederum das Dispose der Member aufruft. Klingt gut. Hab ich was übersehen?
Eben, Dispose infiziert alles, mit dem es in Kontakt kommt. Das kann nicht nur wahnsinnig aufwändig zu coden werden, sondern auch wahnsinnig undurchsichtig und extrem schwer zu managen. Zumindest meiner Erfahrung nach. Wer mal OpenGL mit C# gecodet hat, weiß vielleicht was ich meine. Fast jedes Mal, wenn ich mit C# arbeite, komm ich früher oder später an den Punkt, wo ich einfach nurmehr schreien möchte: Ein Königreich für RAII...
Btw, weil hier einige über die Geschichte mit dem Finalizer diskutieren: Die Aussage, dass es irgendwann eh disposed wird, geht am Sinn von IDisposable vorbei.
GPC schrieb:
Bzgl. des vorgestellten Patterns möchte ich noch sagen, dass man das nur braucht, wenn man tatsächlich unmanaged resources hat. Hat man nur managed resources, braucht man a) keinen Finalizer und b) kein Dispose(bool)
Sobald du auch nur eine Datei öffnest, hast du schon unmanaged Ressourcen, denn alles außer Speicher am GC Heap ist eine unmanaged Ressource...
Aber ja, C# ist eine nette Sprache, ich mag es auch, so lange man keine unmanaged Ressourcen braucht. Denn IDisposable ist imo keine gute Lösung, wenn es auch, aufgrund des GC, die einzige Möglichkeit ist. Und C# ist zumindest noch besser als Java was das angeht...
-
dot schrieb:
GPC schrieb:
Bzgl. des vorgestellten Patterns möchte ich noch sagen, dass man das nur braucht, wenn man tatsächlich unmanaged resources hat. Hat man nur managed resources, braucht man a) keinen Finalizer und b) kein Dispose(bool)
Sobald du auch nur eine Datei öffnest, hast du schon unmanaged Ressourcen, denn alles außer Speicher am GC Heap ist eine unmanaged Ressource...
Nein, das ist anders gemeint. Es ist überflüssig, in deinem Finalizer deine Managed Resourcen disposen zu wollen, die werden nämlich auch gerade finalisiert. Unmanaged Resourcen haben aber keine Finalizer, die musst du tatsächlich in deinem Finalizer freigeben.
-
dot schrieb:
Und C# ist zumindest noch besser als Java was das angeht...
Wie macht es Jave eigentlich?
-
JavaIstEineInsel schrieb:
dot schrieb:
Und C# ist zumindest noch besser als Java was das angeht...
Wie macht es Jave eigentlich?
Siehe hier: http://www.zfx.info/viewtopic.php?f=4&t=2337