2009-01-19 16 views
4

Aucun des guides/notes/articles qui traitent du modèle IDisposable ne suggère que les membres internes doivent être définis sur null dans la méthode Dispose(bool) (en particulier s'il s'agit de bêtes de mémoire). Je viens de réaliser l'importance de cela tout en déboguant un outil de référence interne. Ce qui se passait autrefois, c'était que ce tampon contenait un grand tableau à l'intérieur. Nous avions l'habitude d'utiliser un tampon statique pour l'ensemble du programme de référence. Une fois que nous en aurons terminé avec le tampon, nous n'aurions aucun moyen de libérer ce tableau interne, nous ne pourrions pas non plus rendre ce tampon libérable (car il était statique). Donc, je crois que, après Dispose(), je crois que la classe devrait faire tout ce qu'elle peut pour libérer toutes les ressources qu'elle utilise et les rendre disponibles à nouveau, même si l'objet n'est pas récupéré par lui-même. GC, et ne pas mettre les membres à zéro, ce qui ne permet pas aux objets internes d'être collectés par le GC implique que l'implémentation de Dispose n'est pas parfaite.Dans l'implémentation de la méthode Dispose (bool), ne devrait-on pas mettre les membres à zéro?

Quelle est votre opinion à ce sujet?

Répondre

6

diffusent des références supplémentaires pendant Dispose est certainement quelque chose que j'essaie de faire, pour deux raisons:

  • elle permet aux objets internes à ordures collectées même si l'objet disposé est toujours portée
  • si les objets internes sont à usage unique, cela signifie que nous les éliminons une seule fois, même si Dispose() est appelée à plusieurs reprises sur l'objet externe

Par exemple, j'ai tendance à utiliser des choses comme:

if(someDisposableObject != null) 
{ 
    someDisposableObject.Dispose(); 
    someDisposableObject = null; 
} 
(for non-disposable, just set to null) 
someNonDisposableObject = null; // etc 

Vous pouvez également définir des événements null:

someEventHandler = null; 

Cela peut aider à réduire l'impact si l'appelant ne peut pas complètement libérer leur référence (ou simplement oublie) pour le moment. Alors que vous devriez essayer de libérer l'objet externe (pour GC), il est relativement facile de prolonger accidentellement la vie de l'objet, par exemple via une variable capturée (méthode anonyme/lambda), un événement, etc.

Si vous avez un finaliseur, alors pendant le processus GC il n'y a aucun avantage à le faire, et vous ne devriez pas vraiment appeler des méthodes sur des objets externes (même Dispose()) - donc en bref: ne faites rien de tout cela lors d'un balayage GC.

+0

Marc, vous devez * toujours * mettre les événements à zéro !!! Cela peut provoquer une fuite de mémoire dans certains cas. Upvote: bonne réponse –

+0

Que "quelques instances" se rapporte probablement à l'infâme problème "d'événements statiques" qui a planté un robot. Tant que l'objet est finalement admissible à la récupération de place, les événements ne provoquent normalement pas directement de fuites de mémoire. Cependant, les événements statiques ne sont jamais collectés - essayez de les éviter si possible ;-p –

+0

Et bien sûr, les événements statiques ne sont pas liés à IDisposable (qui est un concept d'instance). Donc, même si je suis d'accord avec la définition des événements à null, il n'est pas tout à fait vrai d'affirmer que cela peut causer des fuites de mémoire ... mieux vaut libérer tôt, cependant. –

0

Eh bien, en général, ça ne va pas faire la différence. Le seul endroit où cela fera une différence est quand vous avez une référence à un objet sur le gros tas d'objets, le comportement que vous avez déjà vu).

Il y a un bon article sur la LOH qui va dans ce plus en détail ici:

http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

+2

Cela fera une différence chaque fois que la référence à l'objet disposé n'est pas libérée. –

1

Peut-être que je manque votre point, mais une fois votre objet est disposé, la racine ou « sous -root 'représenté par rapport à ses membres a été détaché. Il semble que vous pensiez à la collecte des ordures comme un système de comptage de ref (ce qui peut être fait, mais ... ne l'est généralement pas). Au lieu de cela, considérez-le comme un arbre à plusieurs racines, où chaque objet a des branches pour ce à quoi il est lié. À la fin de la journée, les «racines finales» sont des statistiques et tout ce qui est instancié à partir d'une boucle «principale». Lorsque le ramasse-miettes fonctionne, la façon la plus simple de penser à ce qu'il fait est de considérer qu'il marchera dans la liste des 'vraies racines' et appliquera une 'couleur' ​​à tout ce qu'il peut 'atteindre'.

Maintenant, supposons que le collecteur a accès à 'tout', qu'il soit enraciné ou non. Tout ce qui n'est pas coloré peut être nettoyé.

Pour revenir à votre question initiale, lorsque votre objet est éliminé, on suppose (ou du moins on espère) que personne ne le référence plus. Si tel est le cas, il n'est plus enraciné et ne contribuera donc pas à «colorer» tout ce qu'il touche. Longue histoire plus longue - si annulant des membres dans une routine Dispose corrige quelque chose - je serais vous avez un différent, et vrai, problème que quelqu'un tient un lien vers votre objet disposé, et le gardant «accessible» quand CA ne devrait pas être. Je m'excuse pour ce qui est peut-être le message le plus sur-rempli que j'ai jamais écrit, mais j'utilise en quelque sorte les termes standards.

+0

Je pense que cela peut être un effort pour minimiser la quantité de balayages requis pour libérer ces objets. Rappelez-vous, le GC fonctionne selon le processus: des objets colorés et colorés. –

+0

@Joe Vous avez écrit: "quand votre objet est éliminé, on suppose (ou du moins on espère) que personne ne le référence plus" La disposition n'est pas une assurance qu'un objet n'est pas encore tenu. Peut-être une collection d'objets est-elle disposée après utilisation pour libérer des ressources mais toujours conservée dans la collection pour un processus ultérieur afin de les supprimer? Ne serait-ce pas simplement une bonne programmation défensive pour libérer des ressources lourdes avec un 'resource = null' dans Dispose()? Vous ne pouvez pas savoir quelles erreurs de codage ou quelle mauvaise pratique peuvent retenir un objet. Ainsi, 'resource = null' semble une bonne pratique pour les ressources lourdes, non? –