Les gestionnaires d'événements empêchent-ils le garbage collection?

183

Si j'ai le code suivant:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;

PClass sera-t-il ramassé? Ou restera-t-il toujours en train de déclencher ses événements chaque fois qu'ils se produisent? Dois-je effectuer les opérations suivantes pour autoriser le garbage collection?

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;
Mark Ingram
la source
11
Je vais suggérer provisoirement aux lecteurs intéressés par cette question qu'il pourrait être utile de se familiariser avec les événements légers / les modèles d'événements faibles, qui n'empêchent PAS le ramassage des ordures. Un bon bootstrap SO pour ce sujet est stackoverflow.com/questions/185931/…
fostandy
20
Remarque pour la postérité: définir la référence sur null retarde simplement le ramasse-miettes en étendant d'une ligne la portée de la référence. .NET n'est pas VB6.
John Saunders

Réponses:

207

Pour la question spécifique "Est-ce que pClass sera garbage collection": l'abonnement aux événements n'a aucun effet sur la collection de pClass (en tant qu'éditeur).

Pour GC en général (en particulier, la cible): cela dépend si MyFunction est statique ou basé sur une instance.

Un délégué (tel qu'un abonnement à un événement) à une méthode d'instance inclut une référence à l'instance. Alors oui, un abonnement à un événement empêchera GC. Cependant, dès que l'objet publiant l'événement (pClass ci-dessus) est éligible pour la collecte, cela cesse d'être un problème.

Notez que c'est unidirectionnel; c'est à dire si nous avons:

publisher.SomeEvent += target.SomeHandler;

alors «éditeur» gardera «cible» en vie, mais «cible» ne maintiendra pas «éditeur» en vie.

Donc non: si pClass doit quand même être collecté, il n'est pas nécessaire de désinscrire les écouteurs. Cependant, si pClass avait une longue durée de vie (plus longue que l'instance avec MyFunction), alors pClass pourrait garder cette instance vivante, il serait donc nécessaire de se désabonner si vous voulez que la cible soit collectée.

Cependant, pour cette raison, les événements statiques sont très dangereux lorsqu'ils sont utilisés avec des gestionnaires basés sur des instances.

Marc Gravell
la source
6
Eh bien, si la question est "est-ce que pClass sera ramassé", alors la réponse "ça dépend si ..." n'est pas réellement correcte. Cela ne dépend de rien, comme Marc lui-même le note plus bas.
Tor Haugen
@Tor - assez juste - je vais clarifier
Marc Gravell
Bien qu'un délégué d'abonnement à un événement n'indique qu'une seule manière, un abonné qui a l'intention de se désabonner d'un événement une fois terminé, aura besoin d'une forme de référence à l'éditeur. Cela WeakReferencepourrait être une bonne idée, et dans certains cas, mais aussi souvent que non, ce sera une bonne idée.
supercat
Une bonne réponse car elle répond également à l'autre moitié de la question (qui n'a pas été posée): l' éditeur empêchera l' abonné d'être GC.
Bob Sammers
Oui, et comme @BobSammers l'a dit, cela pourrait vraiment être un problème si une instance de courte durée, comme un formulaire / fenêtre, s'abonne à un service de longue durée comme un Singleton qui fournit des données par exemple: le Singleton conserve alors une référence , et les objets sont donc gardés en mémoire même quand on pense qu'ils sont déchargés! Soyez donc très prudent lorsque vous utilisez des événements. Nous avons abusé des événements pour notre gros logiciel, et c'est très difficile à résoudre par la suite.
Elo
9

Oui, pClass sera ramassé. L'abonnement aux événements n'implique aucune référence à pClass.

Si non, vous n'aurez pas à détacher le gestionnaire pour que pClass soit ramassé.

Tor Haugen
la source
8

Dès qu'un morceau de mémoire n'est plus référencé, il devient un candidat pour le garbage collection. Lorsque l'instance de votre classe est hors de portée, elle n'est plus référencée par votre programme. Il n'est plus utilisé et peut donc être collecté en toute sécurité.

Si vous ne savez pas si quelque chose sera collecté, posez-vous la question suivante: existe-t-il encore une référence? Les gestionnaires d'événements sont référencés par l'instance d'objet, et non l'inverse.

lvaneenoo
la source
0

pClassseront ramassés. Cependant, si l'extrait de code ci-dessus se trouve dans une autre classe, l'instance de cette classe peut ne pas être effacée si vous ne définissez pas pClasssur null.

Arav
la source