Tengo una clase simple que se define a continuación.
public class Person
{
public Person()
{
}
public override string ToString()
{
return "I Still Exist!";
}
~Person()
{
p = this;
}
public static Person p;
}
En el método principal
public static void Main(string[] args)
{
var x = new Person();
x = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Person.p == null);
}
¿Se supone que el recolector de basura es la referencia principal para Person.p y cuándo exactamente se llamará al destructor?
c#
.net
garbage-collection
Parimal Raj
fuente
fuente
Person1
? Solo veoPerson
. Por último: consulte docs.microsoft.com/dotnet/csharp/programming-guide/… para ver cómo funcionan los finalizadores.Person1
es en realidadPerson
, reparó el error tipográfico.GC.Collect
llamadaRespuestas:
Lo que falta aquí es que el compilador está extendiendo la vida útil de su
x
variable hasta el final del método en el que se define, eso es algo que hace el compilador, pero solo lo hace para una compilación DEPURACIÓN.Si cambia el código para que la variable se defina en un método separado, funcionará como espera.
La salida del siguiente código es:
Y el código:
Así que, básicamente, tu comprensión fue correcta, pero no sabías que el furtivo compilador mantendría viva tu variable hasta después de que llamaste
GC.Collect()
, ¡incluso si la configuraste explícitamente como nula!Como señalé anteriormente, esto solo sucede para una compilación DEBUG, presumiblemente para que pueda inspeccionar los valores de las variables locales mientras se depura hasta el final del método (¡pero eso es solo una suposición!).
El código original funciona como se esperaba para una compilación de lanzamiento, por lo que el siguiente código genera
false, true
una compilación RELEASE yfalse, false
una compilación DEBUG:Como anexo: tenga en cuenta que si hace algo en el finalizador para una clase que hace que una referencia al objeto que se está finalizando sea accesible desde la raíz de un programa, entonces ese objeto NO se recolectará basura a menos que y hasta que ese objeto ya no esté referenciado
En otras palabras, puede darle a un objeto una "suspensión de ejecución" a través del finalizador. Sin embargo, esto generalmente se considera un mal diseño.
Por ejemplo, en el código anterior, donde lo hacemos
_extendMyLifetime = this
en el finalizador, estamos creando una nueva referencia al objeto, por lo que ahora no se recolectará basura hasta que_extendMyLifetime
(y cualquier otra referencia) ya no haga referencia a él.fuente