Dispose() ...
-
Für das freigeben von nicht benutztem Speicher ist der Garbage-Collector zuständig. In welchen Fällen ist es sinnvoll bzw notwendig, die Dispose() Methode aufzurufen ? Reicht der Garbage-Collector nicht alleine aus ? Gelesen habe ich, dass in Fällen in denen viel Speicher verbraucht wird, zB grosse Bitmaps, der Aufruf von Dispose() durchaus Sinn macht. Weiss jemand Rat ?
-
Dispose SOLLTEST du immer aufrufen wenn dein Objekt IDisposable implementiert. IDisposable hat nicht zwangslaeufig was mit dem aufraeumen des Speichers zu tuen sondern auch das freigeben von externen Ressourcen. Wie soll sich der Garbage-Collector darum kuemmern?
-
Firefighter schrieb:
Dispose SOLLTEST du immer aufrufen wenn dein Objekt IDisposable implementiert. IDisposable hat nicht zwangslaeufig was mit dem aufraeumen des Speichers zu tuen sondern auch das freigeben von externen Ressourcen. Wie soll sich der Garbage-Collector darum kuemmern?
Mit der Finalize-Methode natürlich. Bei einem korrekt implementierten Dispose-Pattern kommen sich manuelles Aufrufen von Dispose und GC nicht in die Quere.
In eine idealen Welt würde gelten: Mit dem Aufruf von Dispose kann man unverwaltete Ressourcen vorzeitig freigeben. Tut man das nicht, kommt früher oder später der GC und gibt sie dank Dispose-Pattern und Finalizern frei.
In der realen Welt: Wenn man z.B. viele Bitmaps verarbeitet und nicht Dispose aufruft, gibt es irgendwann eine OutOfMemory-Exception
Irgendwas versagt hier. Der GC sieht die Not nicht oder die NET-Frameworkentwickler haben ihr eigenes Pattern nicht immer korrekt implementiert.
-
µ schrieb:
Firefighter schrieb:
Dispose SOLLTEST du immer aufrufen wenn dein Objekt IDisposable implementiert. IDisposable hat nicht zwangslaeufig was mit dem aufraeumen des Speichers zu tuen sondern auch das freigeben von externen Ressourcen. Wie soll sich der Garbage-Collector darum kuemmern?
Mit der Finalize-Methode natürlich.
Finalize ist eine Art Rettungsschirm, wenn alles andere versagt.
In eine idealen Welt würde gelten: Mit dem Aufruf von Dispose kann man unverwaltete Ressourcen vorzeitig freigeben. Tut man das nicht, kommt früher oder später der GC und gibt sie dank Dispose-Pattern und Finalizern frei.
Der GC verwaltet den Speicher und nur diesen, und er kommt deshalb erst dann ins Spiel, wenn der Speicher voll ist und aufgeräumt werden muss. Wenn du externe Ressourcen belegst, woher soll der GC denn wissen, ob und wann er mal eine Runde Objektfinalisierung einlegen sollte?
In der realen Welt: Wenn man z.B. viele Bitmaps verarbeitet und nicht Dispose aufruft, gibt es irgendwann eine OutOfMemory-Exception
Nix Rolleyes. Soll der GC etwa ständig das Grafiksubsystem fragen, wieviele Bitmap-Ressourcen noch frei sind? Und wieviele Sockets, wie viele Filehandles, wie viele Threads das OS noch hat?
Irgendwas versagt hier. Der GC sieht die Not nicht oder die NET-Frameworkentwickler haben ihr eigenes Pattern nicht immer korrekt implementiert.
Wenn du damit sagen willst, dass es sowas wie Unmanaged Ressourcen nicht geben sollte, OK, das ist mir zu philosophisch, um es zu kommentieren. Das würde wohl mindestens ein in .NET implementiertes OS erfordern. In einer Welt mit Unmanaged Ressourcen geht es aber nicht anders.
-
Bashar schrieb:
In eine idealen Welt würde gelten: Mit dem Aufruf von Dispose kann man unverwaltete Ressourcen vorzeitig freigeben. Tut man das nicht, kommt früher oder später der GC und gibt sie dank Dispose-Pattern und Finalizern frei.
Der GC verwaltet den Speicher und nur diesen, und er kommt deshalb erst dann ins Spiel, wenn der Speicher voll ist und aufgeräumt werden muss. Wenn du externe Ressourcen belegst, woher soll der GC denn wissen, ob und wann er mal eine Runde Objektfinalisierung einlegen sollte?
http://msdn.microsoft.com/en-us/library/system.gc.addmemorypressure.aspx
Bzw. wenn es sich nicht um (unmanaged) Speicher handelt, dann eban
http://msdn.microsoft.com/en-us/library/system.gc.collect.aspx
und zwar genau dann, wenn irgendeine Resourcen-Anforderung schiefgegangen ist.
-
@Bashar
Irgendwie hast Du mich missverstanden.Das Pattern:
class MyResourceWrapper : IDisposable { bool disposed = false; public void Dispose() { CleanUp(true); GC.SuppressFinalize(this); } private void CleanUp(bool disposing) { if (!this.disposed) { if (disposing) { //Hier alle verwalteten Ressourcen freigeben -> Dispose der Felder aufrufen } //Hier alle unverwalteten Ressourcen freigeben } disposed = true; } ~MyResourceWrapper() { CleanUp(false); } }
Bashar schrieb:
Nix Rolleyes. Soll der GC etwa ständig das Grafiksubsystem fragen, wieviele Bitmap-Ressourcen noch frei sind? Und wieviele Sockets, wie viele Filehandles, wie viele Threads das OS noch hat?
Doch Rolleyes.
Ich bearbeite hunderte/tausende Bilder und werfe die Referenz darauf immer sofort wieder weg. (for(){Bitmap b...}) Der GC weiß also dass ich die Objekte der Bitmapklasse nicht mehr benötige. Irgendwann stehen wir kurz vor einer OutOfMem-Exception. An dem Punkt sollte der GC spätestens anlaufen, die Finalizer aufrufen und gemäß obigen Pattern in CleanUp alles freigeben. Also was ist kaputt, wenn der Rettungsschrim nicht funktioniert: Das Dispose-Pattern der Bitmap-Klasse oder der GC, der den Notfall nicht erkennt?
Genau so war auch mein "In einer idealen Welt..." zu verstehen.Ich wollte nicht ausdrücken, dass man sich immer auf Finalizer verlassen soll. Dispose-Aufrufen ist schon gut und richtig. Aber es SOLLTE auch ohne funktionieren wenn der Speicher knapp wird. Ist jetzt klarer wovon ich rede? Vielleicht hätte ich deutlicher machen sollen, dass ich eigentlich nur auf das Speicherproblem eingehe. Dass der GC sonst nicht wissen kann, wann und welche Sockets/Filehandles/etc freizugeben hat, ist völlig richtig.
-
µ schrieb:
Irgendwann stehen wir kurz vor einer OutOfMem-Exception. An dem Punkt sollte der GC spätestens anlaufen, die Finalizer aufrufen und gemäß obigen Pattern in CleanUp alles freigeben. Also was ist kaputt, wenn der Rettungsschrim nicht funktioniert: Das Dispose-Pattern der Bitmap-Klasse oder der GC, der den Notfall nicht erkennt?
Meine Vermutung ist:
Managed-Memory ist noch genügend da, der GC sieht also keinen Bedarf.
Unmanaged-Memory ist allerdings knapp und die OutOfMemory-Exception wird nur aufgrund vom Rückgabewert der GDI+ Funktion geworfen - managed code könnte aber problemlos noch weiterlaufen.
-
µ schrieb:
Ich bearbeite hunderte/tausende Bilder und werfe die Referenz darauf immer sofort wieder weg.
MSDN schrieb:
http://msdn.microsoft.com/en-us/library/8th8381z.aspx
Always call Dispose before you release your last reference to the Image. Otherwise, the resources it is using will not be freed until the garbage collector calls the Image object's Finalize method.
Also sowas wie:
(for(){using(Bitmap b){...}})
Kann da Wunder wirken.
-
@geeky
Gute Erklärung. Könnte passen.@loks
Es geht nicht um eine Lösung des Problems, die mir natürlich bekannt ist. Sondern die Frage warum es überhaupt ein Problem ist.
-
Ich denke mal die Implementierung eines vollkommenen GC ist nicht wirklich trivial. Wenn du Ideen hast wie man es verbessern koennte, warum wendest du dich damit nich an MS, die freuen sich sicherlich ueber solche Informationen
-
µ schrieb:
@Bashar
Irgendwie hast Du mich missverstanden.Stimmt, sorry. Ich hab das
OutOfMemoryException
überlesen und da mental irgendeine generischeExterneRessourceErschöpftException
draus gemacht (halt eine Bedingung, die der GC nicht erkennen kann).
-
Die OutOfMemoryException kommt bei Bitmaps aber doch von den 'unmanaged' Ressourcen, daher kann der GC (der nur den 'managed'-Speicher verwaltet) diese doch gar nicht erkennen!
-
verlesen