2010-09-19 13 views
2

Voici un article sur GC peut se produire au moment de l'exécution de code inattendu:Comment puis-je reproduire ce scénario Garbage Collection .NET

vie, GC.KeepAlive, poignée de recyclage - par cbrumme http://blogs.msdn.com/b/cbrumme/archive/2003/04/19/51365.aspx?wa=wsignin1.0

Ma question est comment puis-je reproduire GC forcé au point mentionné dans l'article? J'ai essayé de mettre GC.Collect() au début de OperateOnHandle(), et ai défini le destructeur pour la classe C mais ne semble pas fonctionner. Destructeur est invoqué toujours à la fin du programme.

@Jon, merci de m'avoir averti que je n'ai plus de débogueur. Maintenant, je suis capable de reproduire le problème décrit dans l'article, en utilisant la version de sortie optimisée de débogueur. Cela prouve que ce comportement GC ne change pas depuis .NET v1.

Code I utilisé:

class C1 
{ 
    // Some unmanaged resource handle 
    IntPtr _handle = IntPtr.Zero; 

    static void OperateOnHandle(IntPtr h) 
    { 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     Console.WriteLine("After GC.Collect() call"); 

     // Use the IntPtr here. Oops, invalid operation 
    } 

    public void m() 
    { 
     OperateOnHandle(_handle); 
    } 

    ~C1() 
    { 
     // Release and destroy IntPtr here 
     Console.WriteLine("In destructor"); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     C1 aC = new C1(); 
     aC.m(); 
    } 
} 

Sortie:

En destructor Après GC.Collect() appellent

+0

C'est un vieil article (2003), il se peut donc que les dernières versions de .Net Framework aient abouti à un comportement différent. –

+0

L'article était vraiment * sur * SafeHandle. Il ne pouvait pas encore le divulguer. –

+0

@Hans, oui vous avez raison. Il s'agit vraiment de SafeHandler. – Sheen

Répondre

2

Gardez à l'esprit que cet article est de 2003, qui utilisait v1 CLR . Nous sommes maintenant sur CLR v4 (bien qu'il n'y ait pas de v3) donc je ne suis pas vraiment surpris que vous ne voyiez pas exactement le même comportement.

Actuellement, je ne peux même pas accéder à la page liée, et vous n'avez pas inclus une description de ce que la page décrit. Est-ce la possibilité qu'un objet soit collecté avant la fin d'une méthode d'instance?

Si tel est le cas, la raison la plus évidente pour laquelle vous pourriez avoir des problèmes de reproduction est si vous utilisez le débogueur. Le garbage collector est beaucoup plus agressif lorsque vous exécutez sans un débogueur attaché.

Voici un programme court mais complet qui démontre la question lors de l'exécution pas dans un débogueur:

using System; 

class ClassWithFinalizer 
{ 
    private int value; 

    public ClassWithFinalizer(int value) 
    { 
     this.value = value; 
    } 

    ~ClassWithFinalizer() 
    { 
     Console.WriteLine("Finalizer running!"); 
    } 

    public void ShowValue() 
    { 
     Console.WriteLine(value); 
     Console.WriteLine("Calling GC.Collect()"); 
     GC.Collect(); 
     Console.WriteLine("Calling GC.WaitForPendingFinalizers()"); 
     GC.WaitForPendingFinalizers(); 
     Console.WriteLine("End of method"); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     var x = new ClassWithFinalizer(10); 
     x.ShowValue(); 
    } 
} 

Compilation (optimisé et sans symboles de débogage, juste pour lui donner la meilleure chance!):

csc /o+ /debug- Test.cs 

exécuter maintenant, avec la sortie:

c:\users\Jon\Test>test 
10 
Calling GC.Collect() 
Calling GC.WaitForPendingFinalizers() 
Finalizer running! 
End of method 

Notez comment fonctionne le finaliseur être donc la méthode est terminée.

Testé avec .NET 4 et .NET 3.5.

+0

Mettez Console.ReadLine() à la fin de Main() pour reproduire le problème de l'OP. –

+0

@Hans: Non ... Je viens de mettre Console.ReadLine() et la fin, et il se comporte de la même manière. Le finaliseur est appelé avant la fin de la méthode. –

+0

merci pour votre exemple. – Sheen