2010-11-29 27 views
2

Je suis occupé à être confus au sujet de la destruction non-déterministe. Dans une réponse à un autre question j'ai reçu le conseil que les destructeurs/finaliseurs (que je suppose être la même chose dans C#, c'est-à-dire la fonction appelée ~ classname()) sont chers et non requis. Mais en regardant this par exemple un destructeur est utilisé et à partir du commentaire sonne comme il peut être vital. Quelqu'un a-t-il reçu des conseils sur la façon dont tout cela s'accorde et dois-je retirer le destructeur de mon code?Utilisation destructor/finaliser cher?

Merci encore.

Répondre

3

Vous ne devez inclure un finaliseur que si a absolument pour effectuer un nettoyage à un moment donné, qu'il soit exécuté explicitement ou non. Dans de tels cas, vous devriez toujours avoir un moyen explicite d'effectuer le nettoyage en temps opportun de toute façon, et cela devrait supprimer la finalisation de toute façon, afin que les «bons» clients ne voient aucune pénalité de performance.

Vous normalement besoin d'un finaliseur si vous avez une poignée directe aux ressources non gérés - si vous avez seulement une référence à une autre classe qui a une poignée sur la ressource (par exemple FileStream) alors vous devriez laisser à la autre classe pour avoir un finaliseur.

Avec l'avènement de SafeHandle dans .NET 2.0, les situations où il vaut la peine d'écrire votre propre finaliseur sont very rare indeed. La pénalité de performance des finaliseurs est qu'ils font vivre vos objets plus longtemps qu'ils n'en ont besoin: dans le premier cycle du GC où ils sont considérés comme éligibles à la collecte, ils sont placés dans la file d'attente du la prochaine génération comme tout autre objet qui survit à un cycle GC. Le finaliseur s'exécutera ensuite dans un autre thread (à un moment donné) et seulement puis seront-ils éligibles pour être réellement collectés. Donc, au lieu de (disons) être recueillis dans la première collection gen1, ils vivent sur cette collection jusqu'à la prochaine gen2, ce qui peut être considérablement plus tard.

+0

Oui, dommage que même la version Fx4 de ce lien ne mentionne pas SafeHandle. –

+0

Une pénalité de performance plus importante est que tous les objets référencés par un objet finalisable ne seront pas collectables pour une autre génération, de même que tous les objets référencés par ceux-ci, ou les objets référencés par ceux-ci, etc. Si un objet référence, directement ou indirectement , objets qui ne seront pas nécessaires lors de la finalisation, l'objet ne doit pas avoir de finaliseur. Au lieu de cela, les choses qui sont réellement nécessaires pour la finalisation devraient être encapsulées dans leur propre classe finalisable, et l'objet plus grand devrait contenir une référence à cela. – supercat

1

Habituellement, l'implémentation d'un destructeur est utile dans le cas où: lorsqu'il n'est pas garanti, ce code client ferme correctement toutes les ressources (flux de fichiers, connexions db etc.). Donc, si le code client échoue à le faire, vous aurez du code, qui le fermera, ce qui est mieux que de laisser les ressources ouvertes.

+0

sauf si ces ressources ont leur propre destructeur, comme tous vos exemples. –

1

Vous avez uniquement besoin du modèle jetable complet lorsque vous traitez directement avec une ressource non gérée. Et puis c'est à votre code appelant de vous assurer que le destructeur n'est (presque) jamais utilisé.

Lorsque vous traitez avec des ressources gérées (= propriété indirecte des ressources non gérés), le destructor est inutile:

class FileWrapper 
{ 
    private FileStream fs; // managed resource 

    ~FileWrapper() 
    { 
     if (fs != null) 
      fs.Dispose(); // fs is already on the GC finalizer queue 
    } 
} 

Chaque fois qu'un objet FileWrapper est recueilli par le GC, il est certain que l'objet fs est le même lot. L'appel à fs.Dispose() est donc inutile, ne testant que le comportement correct (permettant plusieurs appels) du FileStream.Dispose().

Le seul destructeur utile ici est celui de FileStream.

+0

@LukeH: Non, c'est sûr. Il aurait pu être éliminé mais pas collecté. La sécurité de type tient toujours dans un destructeur. Et il n'y a pas de condition de course non plus. –

+1

Oui, vous avez raison, je ne pense pas directement ce matin! – LukeH