Finalizer vs. IDisposable

Eine Frage kam während meines aktuellen Kurses auf: Ist das IDisposable Pattern tatsächlich performanter als einfach nur einen Finalizer zu definieren?

Ja - bereits bei relativ wenigen Objekten ist der Unterschied gravierend!

Der Performancevergleich

Zum Vergleich habe ich zwei Klassen definiert, die Eine lediglich mit einem Finalizer, die Andere mit dem bekannten IDisposable Pattern. Anschließend erzeuge ich jeweils 2.000 Objekte, setze sie null bzw. rufe vorher noch Dispose() auf und anschließend stoße ich den Garbage Collector mittels GC.Collect() an.

Das Ergebnis hat mich dabei selbst fast erstaunt:

Time needed with just the finalizer:     273,8736 ms
Time needed with the disposable pattern: 189,6048 ms

 

Wenn man die Anwendung mehrfach startet, variieren die Ergebnisse, manchmal ist auch die Finalizer Variante schneller. Der Grundtenor ist allerdings: Mit dem IDisposable Pattern ist man im Schnitt gute 150 ms schneller!

Wie funktioniert IDisposable?

IDisposable ist ein in .NET standardmäßig verfügbares Interface, welches die Methode Dispose() definiert. Diese sollte verwendet werden um geöffnete Ressourcen vor der Objektzerstörung zu schließen (Dateien, SQL Verbindungen, etc.). Dadurch erhält man den Vorteil selbst bestimmen zu können, *wann* der Destruktor-Code abläuft - den Zeitpunkt der Objektzerstörung kann man trotzdem nicht beeinflussen.

Um jedoch für den Fall gewappnet zu sein, dass hin und wieder der Dispose()-Aufruf vergessen wird, sollte man trotzdem einen Finalizer implementieren, der eine eigene (private) Überladung der Dispose Methode aufruft. Dieses Dispose hat einen bool Parameter den man dazu nutzen kann um festzustellen, ob das Dispose() nun durch einen eigenen Aufruf, oder durch den Finalizer aufgerufen wurde.

Das Grundproblem des enormen Performanceverbrauchs des Finalizers liegt in seiner Natur. Der Finalizer (in anderen Sprachen auch Destruktor genannt) wird dann aufgerufen wenn das betreffende Objekt zerstört wird. Da in .NET der Garbage Collector dafür verantwortlich ist und dieser mit einer sehr hohen Priorität abläuft, läuft auch der Finalizer Code mit dieser Priorität. Zusätzlich zu diesem Performanceverlust kommt noch eine Besonderheit in der Implementierung im Garbage Collector, die die ganze Sache noch etwas verlangsamt (damit möchte ich euch vorerst nicht langweilen ;) ).

Code, et cetera

Ich habe das Testprogramm unter http://github.com/picaschaf/DotNet-Experimental-Collection veröffentlicht und freue mich über alle Downloads/Kommentare/Erweiterungen.

Schöne Grüße und viel Spaß beim Einsatz des IDisposable Patterns,

Alexander Nassian

Sie haben Fragen zu unseren Trainings? Sie wollen eine Anfrage starten?
Einfach unser Kontaktformular ausfüllen und wir melden uns bei Ihnen.

+49 81 04 - 90 85 25 0