J'ai une classe simple définie comme ci-dessous.
public class Person
{
public Person()
{
}
public override string ToString()
{
return "I Still Exist!";
}
~Person()
{
p = this;
}
public static Person p;
}
Dans la méthode principale
public static void Main(string[] args)
{
var x = new Person();
x = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Person.p == null);
}
Le garbage collector est-il censé servir de référence principale pour Person.p et quand exactement le destructeur sera-t-il appelé?
c#
.net
garbage-collection
Parimal Raj
la source
la source
Person1
? Je vois seulementPerson
. Dernier: voir docs.microsoft.com/dotnet/csharp/programming-guide/… pour le fonctionnement des finaliseurs.Person1
est en faitPerson
, a corrigé la faute de frappe.GC.Collect
appelRéponses:
La chose qui vous manque ici est que le compilateur prolonge la durée de vie de votre
x
variable jusqu'à la fin de la méthode dans laquelle elle est définie - c'est juste quelque chose que le compilateur fait - mais il ne le fait que pour une construction DEBUG.Si vous modifiez le code afin que la variable soit définie dans une méthode distincte, cela fonctionnera comme prévu.
La sortie du code suivant est:
Et le code:
Donc, fondamentalement, votre compréhension était correcte, mais vous ne saviez pas que le compilateur sournois allait garder votre variable en vie jusqu'à ce que vous l'appeliez
GC.Collect()
- même si vous la définissez explicitement sur null!Comme je l'ai noté ci-dessus, cela ne se produit que pour une build DEBUG - probablement pour que vous puissiez inspecter les valeurs des variables locales pendant le débogage jusqu'à la fin de la méthode (mais c'est juste une supposition!).
Le code d'origine FONCTIONNE comme prévu pour une build de version - donc le code suivant sort
false, true
pour une build RELEASE etfalse, false
pour une build DEBUG:En tant qu'additif: notez que si vous faites quelque chose dans le finaliseur pour une classe qui fait qu'une référence à l'objet en cours de finalisation est accessible à partir d'une racine de programme, alors cet objet ne sera PAS récupéré à moins que et jusqu'à ce que cet objet ne soit plus référencé.
En d'autres termes, vous pouvez donner à un objet un "sursis d'exécution" via le finaliseur. Ceci est généralement considéré comme une mauvaise conception!
Par exemple, dans le code ci-dessus, où nous le faisons
_extendMyLifetime = this
dans le finaliseur, nous créons une nouvelle référence à l'objet, il ne sera donc plus récupéré tant que_extendMyLifetime
(et toute autre référence) ne le référencera plus.la source