11
votes

Disposer de la question

J'ai un certain nombre de classes qui ont des variables membres privées qui mettent en œuvre IDisposable (minuteries, brosses, etc.). Ai-je besoin de tout faire pour assurer ces variables sont nettoyés correctement par le .NET Framework?

La littérature que je suis venu à travers fait référence aux « ressources gérées » par rapport aux « ressources non gérés ». Ces termes me sont source de confusion parce que vous pouvez avoir une classe gérée qui implémente des fonctionnalités en utilisant des ressources non gérés. Est-ce considéré comme une « ressource non gérée » ou « ressource gérée »?

Si je comprends bien, si vous n'êtes pas appeler Dispose () sur un objet qui implémente IDisposable, alors les ressources ne sont pas libérées tant que la sortie de l'application. Cette situation pourrait provoquer des exceptions OutOfMemory lors de l'exécution du programme pendant une longue période de temps.

Comment puis-je être sûr que mon code est le bon déroulement gestion des ressources? Il est important pour ces objets parce qu'ils sont des contrôles personnalisés et il peut y avoir beaucoup de dessin qui consomme des ressources IDisposable. J'utilise le C # using chaque fois que je peux, mais parfois je dois faire un objet qui implémente IDisposable une variable membre, et la déclaration à l'aide ne me aider.


1 commentaires

FYI - Si vous voulez plus d'informations, j'ai écrit sur ce scénario ici: REEDCOPSEY.com/2009/04/19/...


7 Réponses :


9
votes

Oui - Si votre classe "contient" un Idisposable , cette classe doit presque implémenter idisposable aussi.

Les ressources "gérées" sont fondamentalement la mémoire. Les ressources "non gérées" peuvent être des poignées de fichier, des connexions réseau, des poignées aux objets graphiques, etc. Dans la plupart des cas, les types directs accès aux poignées natives ont des finaliseurs. La ressource sera donc libérée à un moment donné, mais Il est toujours préférable de le libérer explicitement - dans certains cas (par exemple avec httpwebreffonse ), il peut y avoir un nombre limité de ces ressources disponibles (connexions dans un pool de connexion à un seul hôte dans ce cas) et vous peut finir par chronométrer dans l'attente d'une ressource «morte» à libérer.

Si possible, il est plus gentil pas d'avoir de tels membres de classe en premier lieu - les avoir comme paramètres de méthode des variables locales, etc., afin que vous puissiez les utiliser, puis les fermer sans attacher la durée de vie de la ressource à la durée de vie de votre objet. Cependant, dans certains cas, ce n'est pas approprié - dans quel cas vous devriez mettre en œuvre Idisposable .


1 commentaires

Je pense qu'il est important de noter que les ressources "non gérées" peuvent être pratiquement n'importe quoi, et n'importe où; Ils peuvent exister entièrement dans le monde géré (par exemple, une classe qui alloue des articles à partir d'une piscine détenue dans un tableau statique de manière à minimiser la pression de GC) ou peut exister quelque part autre que la machine actuelle (par exemple, une machine distante peut avoir obtenu des exclusives exclusives. accès à un enregistrement de base de données). Fondamentalement, tout ce que le GC ne saura pas nettoyer.



1
votes

Si votre classe a des variables de membre qui implémentent Idisposable, votre classe devrait également la mettre en œuvre. Vous nettoyez ce que vous possédez.


0 commentaires

0
votes

1) Vous pouvez utiliser un outil de profil de mémoire, il y en a beaucoup autour du Web, le mieux que je connaisse d'être le profileur des fourmis de Reg Gate.

2) Ma règle de base est que les événements doivent toujours être désinscrits et les objets jetables (flux, etc.) seront automatiquement disposés si elles sont des variables membres et l'objet qui les détient est détruit. Si vous créez un objet jetable local dans une méthode par exemple, vous devez le disposer ou simplement le mettre dans un en utilisant la déclaration et l'oublier;)


0 commentaires

1
votes

Vous avez de bonnes informations et certaines désinformations à votre compréhension.

Le long et court signifie que vous devez Dispose () tout ce qui implémente Idisposable .

Etre comme ce sont des variables de membre privé de votre classe, et si ceux-ci sont censés être disponibles pour la durée de vie des instances de cette classe, votre classe doit également mettre en œuvre Idisposable et jetez () de ces types dans son propre jetez () méthode.

Si ces variables de membre privé ont une durée de vie limitée (c'est-à-dire dans une seule méthode), il suffit de les envelopper dans un en utilisant le bloc .


0 commentaires

2
votes

Les directives iDisposables très complètes sont ici < / a>.

éliminer de manière transitoire les champs jetables définis dans votre type de votre méthode de jet.

Vous devez appeler () sur tous les champs Dont le cycle de vie de votre objet contrôle. Par exemple, envisagez un cas où votre objet possède un champ de Textreader privé. Dans votre type Disposer, vous devriez appeler le dispositif d'élimination de l'objet Textreader, qui sera à son tour, disposez de ses champs jetables (flux et codage, pour exemple), et ainsi de suite. Si mis en œuvre à l'intérieur d'un dispositif (BOOL disposant) méthode, cela ne devrait se produire que si le paramètre de disposition est True-toucher d'autres objets gérés n'est pas autorisé pendant finalisation. En outre, si votre objet ne possède pas une donnée objet jetable, il ne devrait pas tenter de le disposer, comme d'autres le code pourrait toujours compter sur elle être actif. Ces deux pourraient conduire à bogues subtils à détecter.

mettez-le en train de mettre en œuvre le motif d'élimination lorsque votre type est désaltéré et contient des ressources qui doivent explicitement être ou peuvent être libérées, pour Exemple de poignées brutes ou d'autres ressources non gérées.

Ce modèle fournit un moyen normalisé pour les développeurs de déterminisciquement Détruire ou des ressources libres appartenant à un objet. Il aident également les sous-classes Pour libérer correctement les ressources de la classe de base.

"ressource non gérée" fait généralement référence aux cas où votre code renvoie des poignées natales directement (poignées de fichier, connexions, sockets, etc.). Dans ce cas, vous devrez également mettre en œuvre finaliser ou utiliser SafeHandle . La plupart du temps, vous faites référence à des poignées natales indirectement , via des classes .NET comme Textreader. Dans ce cas, vous pouvez simplement utiliser "Utilisation" ou, si vous écrivez la bibliothèque, implémentez Idisposable de manière transitive.


0 commentaires

9
votes

Trois règles simples.

Une ressource gérée est tout ce qui implémente Idisposable . Une ressource non gérée est quelque chose comme un gérer que vous avez eu via p / invoke. Une classe comme SafeHandle (ou une dérivée de SafeHandle ) possède une ressource non gérée, mais elle est considérée comme une ressource gérée elle-même. Donc, toute classe qui possède une ressource non gérée est elle-même une ressource gérée.

Depuis que vous avez une classe de ressources gérées, suivez la règle 2: Implémente Idisposable (mais pas un finisseur).

Idisposable permet un nettoyage antérieur. Si vous ne l'appelez pas, les ressources seront nettoyées de toute façon (elles ne seront pas suspendues avant la sortie du processus); Ils seront simplement nettoyés plus tard et vous n'avez pas le choix de quand ils sont nettoyés.


9 commentaires

Merci pour la réponse claire. C'est ce que je cherchais. J'ai vu tant de blogs avec des informations conflictuelles. La page que vous avez liée est simple et claire.


Votre réponse s'applique-t-elle toujours si je vous dis que la classe hérite du contrôle et n'est pas scellée? Le contrôle a déjà une méthode de disposition.


Héritage des ressources gérées est plus complexe. Microsoft a leur Posséder un modèle plutôt déroutant pour cela. Ce que je recommande est: Remplacer Dispose (bool) (appelant base.dispose (BOOL) ) et disposez de vos ressources gérées uniquement si true est passé dans cette méthode. Sinon, ne rien faire. Dans cette situation, votre classe ne devrait pas avoir de ressources non gérées.


Certaines classes qui implémentent Idisposables seront correctement nettoyées si elles sont abandonnées. Tous ne seront cependant pas tous, cependant. Si une interatrogue appelle une "déclaration de rendement" dans un verrou, l'itémérateur renvoyé par cet itérateur est abandonné sans être épargner, la serrure ne sera jamais libérée.


Personnellement, je n'appellerais pas "tout ce qui implique de mettre en œuvre Idisposable" une ressource gérée - en particulier, je serait de la mémoire d'appeler une ressource gérée, et c'est géré par le collectionneur de la poubelle - alors que j'appellerais tout ce qui bénéficie de l'opinion explicite Nettoyage non géré, directement (une poignée natale ") ou indirectement (via un autre type CLR).


@Jon: Je vois votre point sur la terminologie, mais je souhaite distinguer les ressources natives brutes et les ressources enveloppées CLR. Microsoft utilise parfois les termes "Ressource gérée" pour tout Idisposable < / Code>, et autres fois utilise le (imo maladroit) " Objets gérés qui utilisent des ressources natives »pour se reporter à des types jetables.


@Stephen: Je pense qu'il est raisonnable de faire la distinction entre ces deux, mais je parle généralement de types qui ont un accès direct aux ressources non gérées et à ceux qui ont un accès indirect.


Stephen, j'ai suivi votre suggestion de disposer de département (Bool). J'appelle toujours la base.Dispose (Bool). J'appelle Dispose sur la minuterie si le BOOL est défini sur True. J'ai exécuté le programme dans le débogueur avec un point d'arrêt défini en haut de cette méthode. Le point d'arrêt a été touché après l'application.exit a été appelé, mais le Bool est passé était faux, alors la méthode n'a donc pas exécuté la minuterie.Dispose. C'est le contraire de ce que je m'attendais à arriver.


@Trevor: Ceci est attendu (et correct) si vous n'appelez jamais disposer sur votre classe dérivée. Dans ce cas, votre Dispose est appelé à partir du finaliseur.



0
votes

Je pense qu'il est utile de décrire une ressource gérée est un objet de type de classe qui implémente Idisposable et nécessite un nettoyage, mais peut effectuer un tel nettoyage (généralement à l'aide de finaliser) si elle est abandonnée sans être abandonnée correctement. Une ressource non gérée se réfère généralement à une entité qui nécessite un nettoyage qui ne se produira tout simplement pas si elle est abandonnée sans être en premier. Il est important de noter que le terme "ressource géré" désigne essentiellement exclusivement des objets de type classe (qui remplacent généralement la finalisation, mais dans certains cas peut être les objectifs d'objets d'affaitation), des ressources non gérées peuvent être non seulement Quelque chose , ils peuvent aussi être n'importe où , y compris sur un autre ordinateur.

Je suggérerais que au lieu d'utiliser le terme "ressource", il est plus utile de penser en termes de "responsabilités". L'ouverture d'une connexion de fichier ou de socket crée une responsabilité de la fermer. L'acquisition d'un verrou crée une responsabilité de le libérer. Envoi d'un système distant un message «Accord-moi d'accès exclusif à cet enregistrement» Message crée une responsabilité de l'envoyer un message «J'en ai fait avec cet enregistrement». Si les responsabilités de nettoyage d'un objet peuvent être effectuées même si elle est abandonnée, c'est une "ressource gérée". Sinon, c'est une "ressource non gérée".

Sans simplement catégoriser les choses comme "ressources gérées" ou "ressources non gérées" n'est pas tout à fait suffisante pour décider de la manière dont ils devraient être nettoyés. Certaines responsabilités non gérées peuvent être correctement gérées par une enveloppe de type classe pouvant effectuer tout nettoyage nécessaire en cas d'abandon incorrect. Ces wrappers devraient généralement contenir une quantité minimale d'informations nécessaires pour assumer la responsabilité du nettoyage. D'autres responsabilités ne peuvent pas très bien être traitées automatiquement. Il est souvent préférable de s'assurer que l'élimination est appelé que d'essayer de gérer tout ce qui peut arriver si ce n'est pas le cas.


0 commentaires