Mam prostą klasę, która jest zdefiniowana jak poniżej.
public class Person
{
public Person()
{
}
public override string ToString()
{
return "I Still Exist!";
}
~Person()
{
p = this;
}
public static Person p;
}
W metodzie głównej
public static void Main(string[] args)
{
var x = new Person();
x = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Person.p == null);
}
Czy śmieciarz powinien być głównym źródłem Person.p i kiedy dokładnie zostanie wywołany destruktor?
c#
.net
garbage-collection
Parimal Raj
źródło
źródło
Person1
? Widzę tylkoPerson
. Na koniec : zobacz docs.microsoft.com/dotnet/csharp/programming-guide/…, aby dowiedzieć się, jak działają finalizatory.Person1
jestPerson
naprawione literówka.GC.Collect
połączeniaOdpowiedzi:
Brakuje tutaj tego, że kompilator wydłuża czas życia
x
zmiennej aż do końca metody, w której jest zdefiniowany - to jest po prostu kompilator - ale robi to tylko dla kompilacji DEBUG.Jeśli zmienisz kod, tak aby zmienna została zdefiniowana w oddzielnej metodzie, będzie działać zgodnie z oczekiwaniami.
Dane wyjściowe następującego kodu to:
I kod:
Więc w zasadzie zrozumienie było poprawne, ale nie wiedziałem, że podstępne kompilator zamiar utrzymać przy życiu dopóki zmienna po zadzwoniłeś
GC.Collect()
- nawet jeśli jawnie ustawić go na null!Jak zauważyłem powyżej, dzieje się tak tylko w przypadku kompilacji DEBUG - przypuszczalnie po to, aby sprawdzić wartości zmiennych lokalnych podczas debugowania do końca metody (ale to tylko przypuszczenie!).
Oryginalny kod NIE działa zgodnie z oczekiwaniami w przypadku kompilacji wydania - więc następujące dane wyjściowe
false, true
dla kompilacji RELEASE ifalse, false
kompilacji DEBUG:Jako uzupełnienie: Zauważ, że jeśli zrobisz coś w finalizatorze dla klasy, która powoduje, że odwołanie do finalizowanego obiektu jest osiągalne z katalogu głównego programu, wówczas ten obiekt NIE zostanie wyrzucony, dopóki i ten obiekt już nie będzie o którym mowa.
Innymi słowy, można nadać obiektowi „wstrzymanie wykonania” za pośrednictwem finalizatora. Jest to jednak ogólnie uważane za zły projekt!
Na przykład w powyższym kodzie, w którym robimy to
_extendMyLifetime = this
w finalizatorze, tworzymy nowe odwołanie do obiektu, więc nie będzie ono teraz zbierane w pamięci, dopóki_extendMyLifetime
(i wszelkie inne odniesienia) nie będą już do niego odwoływać.źródło