2012-12-17 5 views
5

Oto akademickie pytanie dotyczące finalizacji i gromadzenia obiektów w C#/.NET. Odczyt w tle to sekcja 3.9 specyfikacji języka C#, Automatyczne zarządzanie pamięcią.WeakReference Behavior Gdy obiekt jest skończony, ale jeszcze nie zebrano śmieci

Gdy nie ma wyraźnych odniesień do obiektu, może on zostać utracony. Staje się "uprawniony do zniszczenia". W pewnym momencie w przyszłości (np. Jeśli wymuszasz zbieranie śmieci), destruktor obiektu zostanie uruchomiony.

W destruktorze, jeśli zapiszesz odniesienie do obiektu, obiekt zostanie sfinalizowany, ale nie będzie można go odebrać. Może to prowadzić do tego, że obiekt znajduje się w stanie, w którym został sfinalizowany, ale nie został zebrany. Sekcja 3.9 specyfikacji ma tego przykład.

W tym momencie obiekt naprawdę żyje, ponieważ nie został jeszcze zebrany. Jednak WeakReference, odwołując się do obiektu, zgłasza wartość false dla wartości IsAlive, wskazując, że obiekt został zebrany.

Podstawowe pytanie brzmi: czym jest własność raportu IsAlive? Wiemy, że nie możemy ufać wartości true dla tej właściwości, ponieważ wartość może stać się fałszywa wkrótce po jej przeczytaniu. Ale wartość false jest godna zaufania i ma na celu wskazanie (zgodnie z dokumentacją), że obiekt został zebrany śmieci. Więc jaka jest właściwość IsAlive, która mówi nam w tym przypadku? Nie ściśle, czy obiekt został zebrany śmieci, ponieważ uważamy, że obiekt jest w stanie sfinalizowanym, ale nie zebrane.

Oto przykład pokazujący zachowanie.

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

Kod programu głównego. Jeśli uruchomisz kod, zobaczysz, że oryginalna WeakReference raportuje IsAlive jako fałszywe, nawet po rekonstrukcji obiektu.

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

Odpowiedz

7

Jeśli przeczytałeś całą dokumentację dla WeakReference, to jasne, że istnieje więcej niż jeden rodzaj słabego odniesienia dostępny. Wartością domyślną jest uzyskanie słabego odniesienia o wartości krótkiej. Ale można również utworzyć słabe odniesienia, które w szczególności uwzględniają scenariusze wskrzeszeń.

Z dokumentacji dla TrackResurrection:

Pobiera wskazanie, czy obiekt odwołuje bieżącego obiektu WeakReference jest śledzona po jego finalizacji.

Jeśli wartość jest prawdą, słabe odniesienie jest długim słabym odwołaniem, a wartość true została określona dla parametru trackResurrection w konstruktorze WeakReference.

Powiedziałbym, że musisz zrozumieć tę część słabych referencji przed interpretacją właściwości IsAlive.

+0

To wydaje się być odpowiedź. W przypadku krótkiej referencji słabej wartość docelowa słabego odniesienia zostanie zmniejszona natychmiast po wywołaniu finalizatora. W przypadku długiego, słabego odniesienia, wartość ta przyjmuje wartość null tylko wtedy, gdy obiekt jest faktycznie zbierany. Dokumentacja MSDN jest trochę ubłocona. Dokumentacja krótkich i długich jest jasna, ale dokumentacja właściwości IsAlive nie jest całkowicie dokładna, ponieważ wskazuje, że IsAlive kończy się fałszem, gdy obiekt jest zbierany.Technicznie, w przypadku krótkich słabych odniesień, fałsz jest fałszywy tylko wtedy, gdy obiekt został sfinalizowany, ale zanim zostanie faktycznie zebrany. –

+3

@SeanSexton: Nieznaczna korekta: słabe odniesienie jest unieważniane, gdy tylko system zauważy, że obiekt byłby uprawniony do zbierania, ale istnienie finalizatora, i dodaje go do listy obiektów, których metody finalizatora powinny być uruchamiane na początku okazja. Finalizator będzie zazwyczaj uruchamiany niedługo później, ale może być arbitralnie opóźniony. Każda krótka "WeakReference", która jest celem obiektu, zostanie unieważniona, gdy tylko obiekt zostanie porzucony, niezależnie od tego, kiedy faktycznie uruchomi się finalizator. – supercat

+0

BTW, dość paskudne dziwactwo, które jest szczególnie denerwujące przy długich słabych odniesieniach, jest tym, że słabe odniesienie, które kwalifikuje się do sfinalizowania, zostanie unieważnione, * nawet jeśli nadal istnieją odniesienia do "WeakReference" i jej celu *. Z tego powodu, kod, który chce użyć długiego słabego odniesienia, aby upewnić się, że obiekt jest dobrze umarły, może potrzebować stworzyć statyczne odwołanie gdzieś do samego 'WeakReference' i mieć jakiś inny obiekt okresowo określający, czy' WeakReference' nadal robi coś użytecznego i zabija statyczne odniesienie, gdy nie jest. – supercat

Powiązane problemy