7
votes

Quand disposerait de la méthode non appelée?

Je lisais Cet article L'autre jour et se demandait pourquoi il y avait un finaliseur avec la méthode de disposition. J'ai lu ici sur pourquoi vous voudrez peut-être ajouter à la Finisseur. Ma curiosité est, quand le finaliseur serait-il appelé sur la méthode d'étalage elle-même? Existe-t-il un exemple de code ou est-il basé sur quelque chose qui se passe sur le système que le logiciel est en cours d'exécution? Si tel est le cas, ce qui pourrait ne pas avoir la méthode de jettement exécutée par le GC.


0 commentaires

5 Réponses :


11
votes

Le but du finaliste ici est simplement une précaution de sécurité contre les fuites de mémoire (si vous vous arrivez pas à appeler Dispose explicitement). Cela signifie également que vous n'avez pas besoin de disposer de vos objets si vous souhaitez qu'ils publient des ressources lorsque le programme arrête, car le GC sera obligé de finaliser et de collecter tous les objets de toute façon.

comme un point connexe, il est important de éliminer l'objet légèrement différemment lorsque vous le faites du finaliseur. xxx

la raison pour laquelle vous ne veuillez pas éliminer les ressources gérées dans votre finaliser est que vous Créerait effectivement des références fortes à ce faire, ce qui pourrait empêcher la GC de faire son travail correctement et les collectera. Les ressources non gérées (par exemple, les poignées Win32 et telles) doivent toujours être explicitement fermées / éliminées, bien sûr, car le CLR n'en a aucune connaissance.


6 commentaires

Et une autre raison de ne pas disposer de ressources gérées dans votre finaliseur ... il est possible qu'ils aient déjà été gc'd au moment de l'exécution de votre finaliste. Essayer de les éliminer quand ils ont déjà été collectés provoqueraient une erreur d'exécution.


@Luke: True, mais cela peut être évité assez facilement en définissant toutes vos références à NULL, puis effectuez une vérification null avant de disposer.


@Noldorin - où l'enregistrement des événements tombe-t-il dans votre exemple? Je comprends parfaitement, ils tomberaient sous gestion, mais si nous avions un objet attaché à cette classe à travers un événement et que nous ne l'enregistrons pas dans la partie non gérée (en supposant que l'utilisateur n'appelle pas d'appeler directement et sa gauche à la GC pour la nettoyer. en haut). Serait-ce sûr / ok de mettre des événements sans enregistrement dans la section gérée pour s'assurer que cela se produit? L'effet secondaire pourrait être que quelqu'un pense qu'ils sont éliminés d'un objet, mais il n'est vraiment jamais disposé à cause du lien d'événement entre cette classe et l'autre.


@ SWDEVMAN81: Je comprends la source de votre préoccupation, mais des événements vraiment ne sont pas différents pour d'autres ressources (elles viennent en fait des emballages autour des délégués de multidiffusion). Néanmoins, l'immatriculture des événements appartient au bloc géré du Dispose méthode. Considérez que s'il s'agit du finaliser appelant la méthode Dispose , vous pouvez garantir que les événements ne seront pas enregistrés immédiatement par le GC dans le cadre de la finalisation.


Il est inutile qu'un objet ait une tentative de finaliseur de se désabonner d'événements auxquels il est souscrit. La seule façon dont le finisseur sera exécuté, c'est si l'objet tenant l'abonnement devient admissible à la collecte des ordures, auquel cas l'abonnement sera discuté.


"Lorsque le programme arrête, puisque le GC sera obligé de finaliser et de collecter tous les objets de toute façon" - le GC n'est pas obligé d'exécuter des finaliseurs à l'arrêt. Cela aura généralement du temps, mais il n'est pas garanti (et ne se produira évidemment pas si le programme est terminé anormalement).



5
votes

Ceci est principalement là pour vous protéger. Vous ne pouvez pas dicter quel sera l'utilisateur final de votre classe. En fournissant un finaliseur en plus d'une méthode de jet, le GC "disposera" de votre objet, libérant vos ressources de manière appropriée, même si l'utilisateur oublie d'appeler () ou mal utilise votre classe.


2 commentaires

Il convient de mentionner que le GC n'est pas déterministe, il n'ya donc aucune garantie de quand, ou même si , votre finaliser sera appelé.


Oui - Si votre programme fonctionne assez longtemps, votre objet est le plus susceptible d'être finalisé. De plus, si cela se ferme proprement, cela deviendra finalisé. Mais il n'y a pas de garantie avec le GC - qui fait partie de la raison pour laquelle Idisposable existe en premier lieu.



2
votes

La méthode d'expulsion doit être explicitement appelée, soit en appelant () ou en ayant l'objet dans une déclaration en utilisant. Le GC appellera toujours le finaliseur, donc s'il y a quelque chose qui doit arriver avant que les objets ne soient disposés que le finaliseur soit au moins vérifier pour vous assurer que tout dans l'objet est nettoyé.

Vous voulez éviter de nettoyer les objets dans le finaliseur si possible, car il provoque un travail supplémentaire par rapport à celui de les disposer avant la main (comme appel à appeler), mais vous devez toujours vérifier au moins dans le finaliseur s'il y a des objets mentionnés autour de ce besoin d'être enlevé.


0 commentaires

3
votes

Le finaliseur est appelé lorsque l'objet est recueilli. Disposer doit être explicitement appelé. Dans le code suivant, le finaliseur sera appelé mais la méthode de jettement n'est pas.

class Foo : IDisposable
{
  public void Dispose()
  {
    Console.WriteLine("Disposed");
  }

  ~Foo()
  {
    Console.WriteLine("Finalized");
  }
}

...

public void Go()
{
  Foo foo = new Foo();
}


2 commentaires

Ceci n'est pas entièrement vrai. Le finaliseur est appelé quelque temps après que l'objet serait autrement admissible à la collecte des ordures (c'est-à-dire que la demande ne fait plus référence l'instance). Toutefois, lorsque le finaliseur doit être exécuté pour l'instance, le CLR raconte réellement l'objet et ne constitue donc pas des ordures recueillies tant que le finisseur n'a pas fonctionné.


Il n'y a pas non plus de garantie qu'un objet jamais soit GC'D ou que son finisseur sera jamais être appelé. C'est pourquoi il est doublement important de vous assurer que vous disposez correctement des objets Idisposables .



1
votes

Une note importante mais subtile non encore mentionnée: un but rarement considéré comme éliminé consiste à empêcher un objet d'être nettoyé prématurément. Les objets atteints de finaliseurs doivent être écrits avec soin, de peur d'une course de finaliseur antérieure que prévu. Un finaliseur ne peut pas fonctionner avant le début de l'appel de la dernière méthode qui sera effectué sur un objet (*), mais il peut parfois être exécuté pendant la dernière méthode appelée si l'objet sera abandonné une fois le la méthode complète. Code qui dispose correctement d'un objet ne peut pas abandonner l'objet avant d'appeler le dispositif, il n'ya donc aucun danger d'un finaliseur qui fait des ravages sur le code qui utilise correctement le dispositif. D'autre part, si la dernière méthode d'utilisation d'un objet utilise des entités qui seront nettoyées dans le finaliseur après sa dernière utilisation de la référence d'objet elle-même, il est possible que le collecteur des ordures d'appeler finaliser sur l'objet et nettoyer des entités qui sont toujours utilisées. Le remède consiste à assurer toute méthode d'appel qui utilise des entités qui vont être nettoyées par un finisseur doivent être suivies à un moment donné par un appel de méthode qui utilise "Ceci". GC.Kekeealive (ceci) est une bonne méthode à utiliser pour cela.

(*) méthodes non virtuelles étendues au code en ligne qui ne fait rien avec l'objet peut être exempté de cette règle, mais dispose généralement d'une méthode virtuelle.


0 commentaires