2012-12-22 16 views
5

Wydaje mi się, że gdy używam klasy WeakReference dla metody delegatów klasy obiektu, klasa obiektu jest zbierana przez GC, ale jest jeszcze inna jej kopia znajdująca się w WeakReference?GC nie zbiera się, gdy WeakReference odwołuje się do delegata?

Trudno mi wyjaśnić słowami. Dam przykład. Mam następujące klasy obiektu o nazwie TestObject:

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; 
    } 

} 

Teraz, w moim głównym aplikacji, spróbuję odnieść się do sposobu TestMethod w TestObject poprzez WeakReference. Intencją jest, aby TestObject mógł zostać zebrany przez GC, gdy wszystkie twarde referencje zniknęły. To jest jak mój główny aplikacji wygląda następująco:

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(); 
    } 

to wyjście po uruchomieniu powyższy kod:

enter image description here

tu jest dziwne. W pierwszej linii, obj można wydrukować "Hello 1", ponieważ została właśnie zainicjowana, a obj przechowywał odwołanie do TestObject. Wszystko dobrze. Następnie obj ustawiono na null z obj = null, a GC został zmuszony do pobrania. Tak więc w drugim wierszu wyjścia, obj jest true, aby być zerowym. Na koniec na ostatniej linii, ponieważ GC zebrał obj, oczekuję, że wyrzuci NullReferenceException lub po prostu nic nie wydrukuje na wyjściu. Jednak wydrukowano to samo, co w pierwszym wierszu wydruku! Czy w tej chwili nie powinno już być zebrane przez GC TestObject ?!

To nasuwa pytanie, czy TestObject, który został po raz pierwszy przechowywany w obj, został później pobrany przez GC, czy nie, po ustawieniu obiektu obj na wartość null.

Gdybym przekazał cały obiekt do WeakReference, tj. new WeakReference(obj), zamiast delegata do WeakReference, działałby idealnie.

Niestety, w moim kodzie muszę przekazać delegatowi WeakReference. Jak mogę ustawić poprawność działania WeakReference, aby GC mógł zebrać obiekt przez odwołanie się do delegata?

Odpowiedz

5

Myślę, że problem leży w teście - nie w ramach. Wygląda na to, że ustawienie zmiennej lokalnej na wartość null nie robi tego, czego się spodziewasz. Jeśli pominąć zmiennej lokalnej w całości, możemy uzyskać oczekiwaną NullReferenceException na „po” linii:

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

Właściwie Twój przykład będzie działał zgodnie z oczekiwaniami, ponieważ nie masz nic z wyjątkiem WeakReference odnosi się do Delegata, więc GC może odbierz, nawet jeśli skomentujesz linię "obj = null"!

This is my result

Może dlatego biegnę kod na oddzielnym wątku (oprócz głównego wątku)?

Powiązane problemy