title image


Smiley Re: Dispose() und Finalize()
Was machst du denn da? Und was willst du genau wissen? Wie man Dispose() aufruft oder wie man das implementiert?



Erstens solltest du besser die GC Funktionen in Ruhe lassen, überlasse das alles dem Runtime. Zweitens solltest du Stream.Close() verwenden. Das ist Dispose(), heisst nur anders weil man traditionell eine Datei (oder was immer) schliesst, und nicht dispost. Dispose() solltest du aufrufen wenn du das Objekt nicht mehr brauchst. Du solltest nur eine Variable auf null setzen wenn du das Objekt nicht mehr benötigst, aber die Variable noch in Scope bleibt. Z.B. in einer Routine wie



public void MyFunc()

{

MyObject mo = new MyObject();

//...

mo.Dispose();

mo = null;

}



ist die Anweisung mo = null völlig überflüssig, weil mo sowieso am Ende der Routine nicht mehr existiert.



Und hier ist ein Text den ich mal zum Thema Dispose() und Finalizer geschrieben habe. Hoffentlich ist das halbwegs verständlich. Meine Deutschkenntnisse sind sehr bescheiden...



Erstens, Dispose() hat nichts mit Garbage Collector zu tun. Zweitens, ein Finalizer ist relativ selten notwendig.



Der Garbage Collector dagegen ist abolut notwendig und funktioniert in .Net sehr effizient. Wir waren sehr überrascht von der Geschwindigkeit unserer .Net Serveranwendungen wo wir tausende von Objekten anlegen jede Sekunde. In .Net werden Heap Objekte (d.h. Reference Types) einfach linear im vorhandenen Heapspeicher angelegt. Es wird nicht versucht ein Stück Speicher im passenden Größe auszusuchen, z.B. Objekte, die nicht mehr gebraucht werden lassen einfach leeren Platz im Heap zurück. Overhead um ein Objekt anzulegen ist deswegen sehr klein. Natürlich bedeutet das, dass Speicher ziemlich schnell voll wird, und deswegen komprimiert werden muss. Und das ist Aufgabe des Garbage Collecters.



Dispose und Finalize sind nur notwendig, wenn Objekte Windows Handles verwalten,oder eingebettete Objekte haben, die solche Handles verwalten, und aus einem einfachen Grund: der Garbage Collector kann nicht wissen was ein Feld vom Typ IntPtr eigentlich darstellt. Offensichtlich müssen Klassen wie FileStream, oder eigene Klassen die aus irgendwelchen Gründen mit APIs und Handles umgehen selber dafür sorgen, dass diese Handles wieder freigegeben werden. Dafür müssen sie irgendeine Methode anbieten, wie etwa .Close() bei FileStream (wir kommen noch zu .Dispose).



Leider kann es sein, dass ein Programm (ierer) es versäumt .Close() aufzurufen. Deshalb kann der Programmierer der Klasse dafür sorgen, dass das doch irgendwann passiert, indem er einen Finalizer programmiert. Diese Funktion wird vom Garbage Collector aufgerufen wenn das Objekt entsorgt wird, da nur der Garbage Collector genau weiss wann es so weit ist. Leider wenn nicht viel in der Anwendung passiert könnte es dauern, bis Finalizer aufregrufen wird, mittlerweile bleiben die Handles (etwa offene Dateien) gültig.



Ein Finalizer ist nicht notwendig in Klassen, die keine Resourcen verwalten (etwa eine Customer Klasse), oder lediglich .Net Klassen wie FileStream benutzen. Im zweiten Fall ist aber .Dispose() notwendig (oder immerhin sehr empfehlenswert).



Da es nicht immer sinnvoll ist eine .Close() anzubieten, haben die MS Entwickler sich ein Design Pattern einfallen lassen, die allgemein für die Freigabe bestimmter Resourcen gedacht ist. Alle .Net Klassen unterstützen dieses Pattern (obwohl in manchen Fällen .Dispose() protected ist, wie bei FileStream, in solchen Fällen wird .Dispose() intern von .Close() aufgerufen). Dispose, oder besser IDisposable Interface ist nicht nur ein Design Pattern, sondern wird auch vom C# Compiler unterstützt (using Anweisung).



Dieses Pattern sieht so aus:



Basis Klasse implementiert IDisposable, und hat deswegen die Methode Dispose() (ohne Parameter).



Diese Dispose() ruft eine zweite protected Methode Dispose(bool) auf. "true" wird übergeben wenn Dipose(bool) von Dispose() aufgerufen wird. Wenn ein Finlaizer vorhanden ist, wird Dispose(bool) mit "false" vom Finalizer aufgerufen.



.Dipose(bool) sollte den Parameter prüfen, und nur wenn true eingebettete Klassen wie etwa FileStreams freigeben. Empfehlensert wenn ein Finalizer vorhanden ist, ist der Aufruf von GC.SuppressFinalize(), da nachdem .Dipose() aufgerufen wurde ist der Finalizer überflüssig. In beiden Fällen sollten irgendwelche Windows Handles freigegeben werden.



Und was bewirkt das ganze? Wenn Dispose() aufgerufen wird, wird die protected Dispose(true) aufgerufen, Unterobjekte werden auch disposed, und irgendwelche Handles freigegeben. Dann ist alles sauber. Wenn Finalizer tatsächlich läuft, weil vergessen wurde .Dispose() aufzurufen (oder vielleicht wegen eines Logikfehlers) wird Dipose(false) aufgerufen, was nur Handles freigibt. In diesem Fall sollten keine anderen Objekte angesprochen werden, da nie sicher sein kann, dass diese Objekte nicht vorher vom GC entsorgt (disposed) wurden.



Das ganze lässt sich in Basisklassen unterbringen, die nützlich sind wenn ein Objekt nicht von irgendeiner bestimmten Basisklasse abgeleitet werden soll, und IDisposable unterstützen sollte. Hier sind Beispiele für solche Basisklassen. Übrig bleibt nur .Dispose(bool) zu überladen in den abgeleiteten Klassen.









using System;



namespace CCommon

{

[Serializable]

[CodeCategory("CCommon")]

public abstract class CDisposableObject : IDisposable

{

[NonSerialized]

protected bool _IsDisposed = false;



public void Dispose()

{

Dispose(true);

_IsDisposed = true;

}



protected virtual void Dispose(bool disposeObjects)

{

//if (disposeObjects)

//{

// Dispose subobjects

//}

// Dispose local Windows handles

}

} // class CDisposableObject

}





using System;



namespace CCommon

{

[Serializable]

[CodeCategory("CCommon")]

public abstract class CFinalizableObject : IDisposable

{

[NonSerialized]

protected bool _IsDisposed = false;





~CFinalizableObject()

{

Dispose(false);

_IsDisposed = true;

}



public void Dispose()

{

Dispose(true);

GC.SuppressFinalize(this);

_IsDisposed = true;

}



protected virtual void Dispose(bool disposeObjects)

{

//if (disposeObjects)

//{

// Dispose subobjects

//}

// Dispose local Windows handles

}

} // class CFinalizableObject

}







Ich hoffe, dass diese Erklärung mindestens ein wenig Licht ins Dunkel gebracht hat...


Moderation is OK, but not to excess...



geschrieben von

Login

E-Mail:
  

Passwort:
  

Beitrag anfügen

Symbol:
 
 
 
 
 
 
 
 
 
 
 
 
 

Überschrift: