Destroy, Finalize und IDisposable
In Delphi für
Win32 hat man immer die Methode
Destroy überschrieben, wenn man Speicher und andere Resourcen (z.B. Datei-Handles) wieder freigeben musste. Diese wurde dann entweder direkt, indirekt über
Free, oder bei Interfaces durch den Referenz-Mechanismus aufgerufen.
Destroy
Auch unter .NET kann man
Destroy nutzen, allerdings darf man sich dann
nicht mehr auf den GC von .NET verlassen, da dieser
Destroy nicht aufrufen würde. Das heißt, wird
Destroy nicht expliziet aufgerufen, so werden die darin enthaltenen nicht-verwalteten Resourcen (Dateihandles, Bitmaps, etc.) nicht freigegeben und es entsteht ein Speicherloch. Von daher sollte man unter .NET auf den Destructor
Destroy ganz verzichten.
Finalize
Finalize wird vom GC aufgerufen, wenn ein Objekt als "nicht mehr refernziert" erkannt wurde. Das heisst, dass man reservierte nicht verwaltete Resourcen hier freigeben sollte.
Finalize hat jedoch einen gravierenden Nachteil: man kann nicht beeinflussen wann es durch den GC aufgerufen wird. Wenn eine Klasse jetzt zum Beispiel eine Datei exklusiv öffnet, kann kein anderer Process (oder der gleiche) noch mal auf diese Datei zugreifen, bis der GC
Finalize aufgerufen hat. Und noch einmal: wann dieses geschieht, dass kann man nicht beeinflussen!
IDisposable
Das
Dispose Pattern beschreibt wie ein Objekt seine Resourcen freigeben kann und somit auch, wie der Nutzer des Objektes dieses einsetzen sollte. Mit
IDisposable wird ein Mechanismus zum freigeben der reservierten Resourcen definiert.
IDisposable definiert nur eine Methode
Dispose();. Diese wird durch das implementierende Objekt aufgerufen, wenn es das implementierte Objekt (also jenes, das die Resourcen blockiert) nicht mehr braucht. In der Implementierung
Dispose(); werden dann alle Resourcen wieder freigegeben.
Hinweis: Nach dem Aufrufen von
Dispose(); wird der vom Objekt belegte Speicher selbst nicht sofort freigegeben, das übernimmt der GC zu einem späteren Zeitpunkt.
Wann nutzt man Finalize, wann nicht
Nutzt ein Objekt lediglich andere verwaltete Resourcen (also i.A. andere Objekte und Standardtypen wie Integer, String, etc.) so sollte man
Finalize nicht implementieren, da das die Freigabe des reservierten Speicher nur auf mind. 2 GC-Aufrufe verzögert. Alle verwalteten Objekte gibt die GC automatisch selbständig frei, wenn diese nicht mehr gebraucht werden.
Finalize sollte man nur nutzen, wenn man nicht verwaltete Resourcen (z.B. Dateihandle, Bitmaps, etc.) freigeben muss.
Braucht man Finalize wenn man IDisposable nutzt
Einfache Antwort:
Ja. IDisposable dient dem Programmierer, der das Objekt einsetzt dazu festzulegen, wenn ein Objekt seine Resourcen freigeben soll. Wenn der Programmierer dieses dann auch
immer tut, dann ist Finalize oft unnötig. Aber wer kann garantieren, dass der Nutzer des Objektes daran auch denkt? Keiner, also kann es zu Speicherlöschern und ähnlichen Problemen kommen. Deshalb sollte man dann auch immer Finalize implementieren. Hier wiederum muss man aufpassen, dass man jetzt evtl. freigegebene Resourcen nicht nochmal versucht freizugeben. Das jedoch hebe ich mir für ein weiteres Tutorial auf.