2012-12-17 5 views
5

Hier ist eine wissenschaftliche Frage zur Objektfinalisierung und -sammlung in C# /. NET. Hintergrundlesung ist Abschnitt 3.9 der C# -Sprachspezifikation Automatic Memory Management.WeakReference-Verhalten, wenn das Objekt abgeschlossen ist, aber noch nicht der gesammelte Müll

Wenn es keine expliziten Verweise auf ein Objekt gibt, kann es zu einer Sammlung von Garbage Collection kommen. Es wird "zur Zerstörung geeignet". Zu einem späteren Zeitpunkt (z. B. wenn Sie die Garbage Collection erzwingen) wird der Destruktor des Objekts ausgeführt.

Wenn Sie im Destruktor einen Verweis auf das Objekt speichern, wird das Objekt zwar finalisiert, kann jedoch nicht erfasst werden. Dies kann dazu führen, dass sich ein Objekt in einem Zustand befindet, in dem es finalisiert, aber nicht gesammelt wurde. Sec 3.9 der Spezifikation hat ein Beispiel dafür.

An diesem Punkt ist das Objekt wirklich noch am Leben, da es noch nicht Müll gesammelt wurde. Eine WeakReference, die sich auf das Objekt bezieht, meldet jedoch einen IsAlive-Wert von false, der angibt, dass das Objekt erfasst wurde.

Die Kernfrage ist das - was ist die IsAlive-Eigenschaft wirklich berichten? Wir wissen, dass wir einem Wert von true für diese Eigenschaft nicht vertrauen können, da der Wert kurz nach dem Lesen falsch werden kann. Aber ein Wert von false ist vertrauenswürdig und soll (gemäß der Dokumentation) anzeigen, dass das Objekt Müll gesammelt wurde. Was sagt uns die IsAlive-Eigenschaft in diesem Fall? Nicht streng, ob das Objekt Müll gesammelt wurde, da wir glauben, dass sich das Objekt in einem finalisierten aber nicht gesammelten Zustand befindet.

Hier ist ein Beispiel, um das Verhalten zu zeigen.

public class Dog 
    { 
     public static Dog KeepDogRef; 



    public string Name { get; set; } 

    public Dog(string name) 
    { 
     Name = name; 
    } 

    ~Dog() 
    { 
     Console.WriteLine("Dog destructor for " + Name + " called"); 
     Dog.KeepDogRef = this; 
    } 

    public void Bark() 
    { 
     Console.WriteLine(Name + " : Woof"); 
    } 
} 

Und Code für Hauptprogramm. Wenn Sie den Code ausführen, sehen Sie, dass die ursprüngliche WeakReference IsAlive als false meldet, auch nachdem wir das Objekt wiederhergestellt haben.

static void Main() 
    { 
     Dog dog = new Dog("Bowser"); 

     WeakReference dogRef = new WeakReference(dog); 

     // Unref Bowser, now eligible for destruction 
     dog = null; 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     // Bowser no longer alive 
     Console.WriteLine(string.Format("Object still alive: {0}", dogRef.IsAlive)); 

     // Bowser alive again 
     Dog newRef = Dog.KeepDogRef; 
     newRef.Bark(); 
    } 
} 

Antwort

7

Wenn Sie die gesamte Dokumentation für WeakReference lesen, ist es klar, dass es mehr als eine Art von schwacher Referenz zur Verfügung steht. Standardmäßig wird eine kurze schwache Referenz erzeugt. Sie können aber auch lange schwache Referenzen erstellen, die speziell Auferstehungsszenarien berücksichtigen.

Aus der Dokumentation für TrackResurrection:

Ruft eine Angabe, ob das Objekt von dem aktuellen WeakReference Objekt referenziert wird verfolgt, nachdem sie fertig gestellt ist.

Wenn wahr, ist die schwache Referenz eine lange schwache Referenz, und für den trackResurrection Parameter im WeakReference Konstruktor wurde true angegeben.

Also ich würde sagen, dass Sie diesen Teil der schwachen Referenzen verstehen müssen, bevor Sie die IsAlive Eigenschaft interpretieren.

+0

Das scheint die Antwort zu sein. Für eine kurze schwache Referenz wird das Ziel der schwachen Referenz null, sobald der Finalizer aufgerufen wird. Für eine lange schwache Referenz wird sie nur null, wenn das Objekt tatsächlich erfasst wird. MSDN Dokumentation ist ein wenig schlammig auf diesem. Die Dokumentation von short vs. long ist klar, aber die Dokumentation der IsAlive-Eigenschaft ist nicht vollständig korrekt, da sie anzeigt, dass IsAlive beim Erfassen des Objekts falsch wird.Technisch wird es bei kurzen schwachen Referenzen erst dann falsch, wenn das Objekt finalisiert wurde, aber bevor es tatsächlich gesammelt wird. –

+3

@SeanSexton: Geringfügige Korrektur: Die schwache Referenz wird ungültig, sobald das System feststellt, dass das Objekt für die Erfassung, aber für die Existenz des Finalisierers infrage kommt, und fügt es zu einer Liste von Objekten hinzu, deren Finalizer-Methoden zuerst ausgeführt werden sollen Gelegenheit. Der Finalizer würde normalerweise ziemlich bald danach ausgeführt werden, aber es könnte willkürlich verzögert werden. Jede kurze "WeakReference", die auf das Objekt abzielt, wird ungültig, sobald das Objekt als aufgegeben erkannt wird, unabhängig davon, wann der Finalizer tatsächlich ausgeführt wird. – supercat

+0

Übrigens, eine ziemlich unangenehme Eigenart, die besonders bei langen schwachen Referenzen störend ist, ist, dass eine schwache Referenz, die für die Finalisierung in Frage kommt, ungültig wird, auch wenn Referenzen sowohl auf die "WeakReference" als auch auf ihr Ziel noch existieren. Aus diesem Grund muss ein Code, der eine lange schwache Referenz verwenden möchte, um sicherzustellen, dass ein Objekt wirklich tot ist, eine statische Referenz irgendwo an der "WeakReference" selbst erstellen und ein anderes Objekt periodisch bestimmen, ob die "WeakReference" tut immer noch etwas Nützliches und tötet die statische Referenz, wenn es nicht ist. – supercat

Verwandte Themen