In welchen Situationen würde ein Verweis auf ein Objekt verweisen, das für die Speicherbereinigung in die Warteschlange gestellt wurde?

7

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).

    
chopperdave 28.02.2012, 21:33
quelle

6 Antworten

12

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%     
Reed Copsey 28.02.2012, 21:36
quelle
4

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 .

    
Enrico Campidoglio 28.02.2012 21:45
quelle
2

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.

    
Alan 28.02.2012 21:45
quelle
1

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:

  1. Entpacke alle Gegenstände, die neu genug sind, um als "Müll" betrachtet zu werden.
  2. Besuchen Sie jedes garbage-collection-root (dh etwas, das inhärent "live" ist), und wenn es noch nicht kopiert wurde, kopieren Sie es in einen neuen Heap, aktualisieren Sie den Verweis auf das neue Objekt und und besuchen alle Elemente, auf die sie verweist (die sie kopieren, wenn sie nicht kopiert wurden). Wenn Sie ein Element im alten Heap, das kopiert wurde, besuchen, aktualisieren Sie einfach die Referenz, mit der Sie es besucht haben.
  3. Untersuchen Sie alle Artikel, die sich für die Finalisierung registriert haben. Wenn es noch nicht kopiert wurde, heben Sie die Registrierung für die Finalisierung auf, fügen Sie jedoch einen Verweis auf eine Liste von Objekten an, die so schnell wie möglich finalisiert werden müssen.
  4. Elemente in der Liste der sofortigen Finalisierung werden als "live" betrachtet, aber da sie noch nicht kopiert wurden, besuchen Sie alle Elemente in dieser Liste und kopieren Sie sie, falls noch nicht kopiert, in den neuen Heap und besuchen Sie alle Elemente zu denen es Referenzen enthält.
  5. Verlasse den alten Haufen, denn niemand wird mehr auf irgendetwas verweisen.

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.

    
supercat 29.02.2012 16:15
quelle
1
  

"... 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%     
Henk Holterman 28.02.2012 22:59
quelle
0

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:

%Vor%

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.

    
paulius_l 28.02.2012 21:45
quelle