Ich lese durch ein C # -Thema auf Dispose () und ~ finalisieren und wann zu verwenden. Der Autor argumentiert, dass Sie keine Referenzen in Ihrem ~ finalize verwenden sollten, da das Objekt, auf das Sie verweisen, möglicherweise bereits erfasst wurde. Das speziell angegebene Beispiel ist ".. Sie haben zwei Objekte, die Referenzen zueinander haben. Wenn Objekt Nr. 1 zuerst erfasst wird, verweist Objekt Nr. 2 auf ein Objekt, das nicht mehr vorhanden ist."
In welchen Szenarien würde eine Instanz eines Objekts in einem Zustand sein, in dem es einen Verweis im Speicher auf ein Objekt hat, das gecodiert wird? Meine Vermutung ist, dass es mindestens zwei verschiedene Szenarien gibt, eine, bei der die Objektreferenz auf ein Objekt zeigt und eine, bei der die Objektreferenz auf eine andere Objektreferenz zeigt (z. B. wenn sie in einer Methode von ref übergeben wurde).
Sie können Objekte haben, die sich gegenseitig referenzieren, und der gesamte Satz kann für GC infrage kommen.
Hier ist ein einfaches Codebeispiel:
%Vor%Normalerweise wird der Speicher nur für Objekte zurückgewonnen, auf die keine Referenz verweist. Objekte mit Finalizern werden jedoch anders behandelt .
Hier ist, was MSDN darüber sagt :
Das Wiederherstellen des von Objekten mit Finalize-Methoden verwendeten Speichers ist erforderlich mindestens zwei Müllsammlungen. Wenn der Garbage Collector ausgeführt wird eine Sammlung, die die Erinnerung an unzugängliche Objekte ohne zurückgewinnt Finalisten. Zu diesem Zeitpunkt kann es die unzugänglichen Objekte nicht sammeln Das haben Finalizer. Stattdessen werden die Einträge für diese Elemente entfernt Objekte aus der Finalisierungswarteschlange und platziert sie in einer Liste von Objekte, die als fertig zur Fertigstellung markiert sind. [...]
Der Garbage Collector ruft die Methoden Finalize für die Objekte in dieser Liste auf und entfernt dann die Einträge aus der Liste. Eine zukünftige Garbage-Collection wird feststellen, dass die finalisierten Objekte wirklich unbrauchbar sind, weil auf sie keine Einträge mehr in der Liste der als fertig zur Fertigstellung markierten Objekte zeigen.
Es gibt also keine Garantie , dass andere Objekte, auf die in einem Finalizer verwiesen wird, immer noch verwendbar sind, wenn Finalize Methode wird vom GC ausgeführt, da möglicherweise bereits während einer früheren Garbage Collection abgeschlossen wurde, während das Objekt selbst darauf wartet abgeschlossen sein .
Kurz gesagt, Objekte, die nicht von einem GC-Root (statisches Feld, Methodenparameter, lokale Variable, registrierte Variable) durch Befolgen der Kette von Referenzen erreichbar sind, sind für die Garbage Collection geeignet. Es ist also durchaus möglich, dass sich beispielsweise Objekt A auf B bezieht, das sich auf C bezieht, das sich auf D bezieht, aber plötzlich annulliert A seinen Bezug auf B, in welchem Fall B, C und D alle gesammelt werden können.
Leider wird die Terminologie für die Garbage-Collection zu oft benutzt, was zu Verwirrung führt. Ein "Disponent" oder "Finalizer" zerstört nicht wirklich ein Objekt, sondern dient vielmehr dazu, die Zerstörung eines Objekts zu verzögern, das andernfalls zerstörungswürdig wäre, bis danach hatte eine Chance, seine Angelegenheiten in Ordnung zu bringen (dh in der Regel durch andere Dinge wissen zu lassen, dass ihre Dienste nicht mehr benötigt werden).
Am einfachsten denken Sie daran, dass der Garbage Collector "stop the world" die folgenden Schritte in der folgenden Reihenfolge ausführt:
Es ist interessant zu bemerken, dass, während einige andere Garbage-Collection-Systeme mit doppelt-indirekten Zeigern für Referenzen arbeiten, der .net Garbage Collector (zumindest der normale "stop the world") direkte Zeiger verwendet. Dies erhöht die Arbeit des Kollektors etwas, aber es verbessert die Effizienz von Code, der Objekte manipuliert. Da die meisten Programme mehr Zeit damit verbringen, Objekte zu manipulieren als Müll zu sammeln, ist dies ein Nettogewinn.
"... dann verweist Objekt 2 auf ein Objekt, das nicht mehr vorhanden ist."
Das wird niemals passieren. Wenn Ihr Code Zugriff auf eine Referenz hat, ist das Objekt, auf das verwiesen wird, immer noch vorhanden. Dies wird Speichersicherheit genannt und dies gilt auch dann, wenn ein Objekt im Hintergrund finalisiert wird. Ein Verweis nie verweist auf eine gesammelte Instanz.
Aber ein existierendes, nicht gesammeltes Objekt könnte bereits Finalisiert (Disposed) sein. Das ist wahrscheinlich, worauf sich Ihre Warnung bezieht.
%Vor%Es gibt einen Begriff namens Wiederauferstehung in .NET.
Kurz gesagt, die Wiederauferstehung kann passieren, wenn sich Ihr Objekt in der Finalisierungswarteschlange befindet, aber wenn der Finalizer ( ~ClassName()
method) aufgerufen wird, wird das Objekt zurück in das Spiel verschoben. Zum Beispiel:
Sie können mehr dazu hier lesen: Auferstehung des Objekts mit GC.ReRegisterForFinalize . Aber ich würde das Buch CLR über C # von Jeffrey Richter wirklich empfehlen, wie es das erklärte Thema in einem der Kapitel ausführlich.
Tags und Links c# garbage-collection dispose finalizer