Einzelnen Beitrag anzeigen

Benutzerbild von sakura
sakura

Registriert seit: 10. Jun 2002
Ort: München
11.412 Beiträge
 
Delphi 11 Alexandria
 
#5

Re: Der .NET Garbage Collector

  Alt 2. Dez 2004, 16:12
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.
Daniel W.