2013-08-13 3 views
4

J'ai cherché sur google ne pas obtenir ce que je veux. Je ne sais pas si j'ai raison ou tort. regard, j'ai essayer de comprendre GC.Collect() est donc ici le code ..Garbage Collection malentendu dans C#

public class SomePublisher 
{ 
    public event EventHandler SomeEvent; 
} 

public class SomeSubscriber 
{ 
    public static int Count; 

    public SomeSubscriber(SomePublisher publisher) 
    { 
     publisher.SomeEvent += new EventHandler(publisher_SomeEvent); 
    } 

    ~SomeSubscriber() 
    { 
     SomeSubscriber.Count++; 
    } 

    private void publisher_SomeEvent(object sender, EventArgs e) 
    { 
     // TODO: something 
    } 
} 

je fais dans mon fil conducteur ..

SomePublisher publisher = new SomePublisher(); 

     for (int i = 0; i < 10; i++) 
     { 
      SomeSubscriber subscriber = new SomeSubscriber(publisher); 
      subscriber = null; 
     } 

     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     Console.WriteLine(SomeSubscriber.Count.ToString()); 
     Console.ReadLine(); 

Je reçois la sortie 0 mais devrait être bebe 10 selon moi parce que GC.Collect() doit avoir supprimer les objets class1 de la mémoire de sorte que class1 destructor doit être appelé donc le nombre doit être augmenté à 10..can n'importe quel corps expliquent cela ..

+5

La principale chose à comprendre à propos de 'GC.Collect();' est que vous ne devriez pas l'utiliser. –

+0

Le testez-vous en mode débogage? –

Répondre

8

(Notez aussi que C# n'a pas de destructeur , il a des finaliseurs. Ce sont des choses très différentes, et vous ne devriez pas les confondre)

Le « problème » est sur cette ligne.

publisher.SomeEvent += new EventHandler(publisher_SomeEvent); 

Cela crée un délégué ciblant la méthode publisher_SomeEvent() de l'instance d'objet particulier, et ajoute ce délégué à la liste d'invocation pour l'événement publisher.SomeEvent. Cet objet délégué fait référence à l'objet cible et empêche l'objet d'être collecté! (C'est une bonne chose - si vous prenez un délégué à une méthode sur un objet particulier, vous ne voulez pas que cet objet soit collecté tant que le délégué n'est plus référencé.)

Ceci ne pose pas de problème pas du tout, mais plutôt l'exécution garde les objets en vie qui sont toujours référencés.

Pour illustrer, c'est la chaîne de références:

SomePublisher -+-> EventHandler --> SomeSubscriber 
       | 
       +-> EventHandler --> SomeSubscriber 
       | 
       +-> (Eight more...) 

Vous devez faire l'une des deux choses avant d'appeler GC.Collect():

  1. Se désabonner de l'événement avant de libérer chaque objet SomePublisher. Cela fera à la fois les instances de délégué EventHandler et les instances SomeSubscriber qu'ils référencent éligibles pour la collecte.
  2. Définissez publisher = null;. Cela entraînera l'éligibilité du graphe d'objet entier pour la collecte.

Dans les deux cas, toutes les références aux objets SomeSubscriber seront publiées.


Notez que la spécification C# fait appeler ces blocs de code "Destructeurs," mais cela est un nom horrible. Ceux qui sont familiers avec les langages collectés par le garbage seront désorientés, car "finalizer" est le terme répandu pour le code qui est invoqué par le garbage collector quand un objet n'est plus joignable. Les développeurs C++ s'attendent en particulier à ce que le destructeur soit exécuté à un moment différent. Alors oui, C# a quelque chose appelé un "destructeur", mais ce n'est pas un destructeur. (Dire quelque chose ne le fait pas!)

+0

je suis désolé pour l'erreur .. j'ai mis à jour mon code..plzz vérifier .. – loop

+0

j'ai déjà utilisé ce GC.WaitForPendingFinalizers(); toujours obtenir 0. – loop

+0

[Cela semble fonctionner pour moi.] (http://ideone.com/wARKwW) Si vous rencontrez toujours des problèmes alors s'il vous plaît envoyer votre exemple de code complet. Ou mieux encore, publiez un [SSCCE] (http://sscce.org) - quelque chose de court je peux copier et coller pour voir exactement le même comportement. Dans le processus de création d'un SSCCE, vous pourriez bien résoudre le problème vous-même. – cdhowie

1

Les finaliseurs d'objets SomeSubcriber ne seront pas appelés jusqu'à la fin. Car même si les objets SomeSubscriber sont définis sur null, sa mémoire est toujours référencée par l'objet SomeEvent de SomePublisher, qui est actif jusqu'à la fin de l'application. Ainsi, lorsque GC.Collect() est appelé, garbage collector ne trouve aucun objet à placer dans la file d'attente du finaliseur.

public SomeSubscriber(SomePublisher publisher) 
{ 
// publisher.SomeEvent += new EventHandler(publisher_SomeEvent); 
} 

Si nous pouvons remplacer le constructeur de SomeSubcriber par le code ci-dessus, nous allons obtenir le résultat que 10 dans la console.