2012-12-22 5 views
5

Es scheint mir, dass, wenn ich die WeakReference Klasse für eine Delegate-Methode einer Objektklasse verwenden, die Objektklasse vom GC gesammelt wird, aber es gibt noch eine weitere Kopie davon in der WeakReference?GC wird nicht erfasst, wenn WeakReference auf einen Delegaten verweist?

Ich finde es schwierig, in Worten zu erklären. Ich werde ein Beispiel geben. Ich habe folgende Objektklasse TestObject genannt:

class TestObject 
{ 
    public string message = ""; 

    private delegate string deleg(); 

    public TestObject(string msg) 
    { 
     message = msg; 
    } 

    public Delegate GetMethod() 
    { 
     deleg tmp = this.TestMethod; 
     return tmp; 
    } 

    public string TestMethod() 
    { 
     return message; 
    } 

} 

Nun, in meiner Hauptanwendung, ich versuche TestMethod über ein WeakReference in TestObject auf das Verfahren zu beziehen. Die Absicht ist, dass die TestObject durch GC gesammelt werden kann, wenn alle harten Referenzen weg sind. Dies ist, wie meine Hauptanwendung wie folgt aussieht:

static void Main(string[] args) 
    { 
     var list = new List<WeakReference>(); 
     var obj = new TestObject("Hello 1"); 
     list.Add(new WeakReference(obj.GetMethod())); 
     Console.WriteLine("Initial obj: " + ((Delegate)list[0].Target).DynamicInvoke());  //Works fine 
     obj = null;  //Now, obj is set to null, the TestObject("Hello 1") can be collected by GC 
     GC.Collect(); //Force GC 
     Console.WriteLine("Is obj null: " + ((obj) == null ? "True" : "False")); 
     Console.WriteLine("After GC collection: " + ((Delegate)list[0].Target).DynamicInvoke()); 
     Console.ReadKey(); 
    } 

Dies ist der Ausgang, wenn ich den obigen Code auszuführen:

enter image description here

Hier ist die seltsame Sache. In der ersten Zeile, obj könnte drucken "Hello 1", weil es gerade initialisiert wurde und obj hielt einen Verweis auf die TestObject. Alles richtig. Als nächstes wurde obj auf null mit obj = null gesetzt und GC wurde gezwungen zu sammeln. Also, in der zweiten Zeile des Ausgangs, obj ist true null zu sein. Schließlich auf der letzten Zeile, seit der GC hat die obj weg gesammelt, ich erwarte, dass es entweder eine NullReferenceException werfen oder nur nichts auf dem Ausgang drucken. Es hat jedoch tatsächlich dasselbe gedruckt wie in der ersten Zeile des Ausgangs! Sollte die TestObject zu diesem Zeitpunkt noch nicht vom GC abgeholt werden ?!

Dies wirft die Frage auf, ob der TestObject, der zuerst in obj gehalten wurde, später vom GC gesammelt wurde oder nicht, nachdem ich obj auf null gesetzt habe.

Wenn ich das ganze Objekt in WeakReference, dh new WeakReference(obj), statt eines Delegierten in die WeakReference übergeben hatte, hätte es perfekt funktioniert.

Leider in meinem Code muss ich in die WeakReference einen Delegaten übergeben. Wie kann ich die WeakReference korrekt funktionieren lassen, damit der GC das Objekt sammeln kann, indem nur auf einen Delegaten verwiesen wird?

Antwort

5

Ich denke, das Problem ist in Ihrem Test - nicht im Rahmen. Es sieht so aus, als ob die lokale Variable auf null gesetzt wird, was nicht erwartet wird. Wenn wir die lokalen Variable ganz überspringen, erhalten wir die erwartete Nullreferenceexception auf der ‚nach‘ Linie:

static void Main(string[] args) 
{ 
    var list = new List<WeakReference>(); 
    //var obj = new TestObject("Hello 1"); 
    list.Add(new WeakReference(new TestObject("Hello 1").GetMethod())); 
    Console.WriteLine("Initial obj: " + ((Delegate)list[0].Target).DynamicInvoke());  //Works fine 
    //obj = null;  //Now, obj is set to null, the TestObject("Hello 1") can be collected by GC 
    GC.Collect(); //Force GC 
    //Console.WriteLine("Is obj null: " + ((obj) == null ? "True" : "False")); 
    Console.WriteLine("After GC collection: " + ((Delegate)list[0].Target).DynamicInvoke()); 
    Console.ReadKey(); 
} 
0

Eigentlich wird Ihr Beispiel wie erwartet ausgeführt, da man nichts außer die WeakReference an den Delegierten bezieht, so GC kann sammle es, auch wenn du die "obj = null" Zeile auskommentierst! (Abgesehen von dem Haupt-Thread)

This is my result

Vielleicht, weil ich an einem separaten Thread den Code renne?