Dois-je Dispose () DataSet et DataTable?

DataSet et DataTable implémentent tous deux IDisposable, donc, par les meilleures pratiques conventionnelles, je devrais appeler leurs méthodes Dispose ().

Cependant, d’après ce que j’ai lu jusqu’à présent, DataSet et DataTable ne contiennent pas de ressources non gérées, alors Dispose () n’en fait pas beaucoup.

De plus, je ne peux pas simplement utiliser using(DataSet myDataSet...) car DataSet possède une collection de DataTables.

Donc, pour être sûr, je dois parcourir myDataSet.Tables, disposer de chacun des DataTables, puis éliminer le DataSet.

Cela vaut-il la peine d’appeler Dispose () sur tous mes DataSets et DataTables?

Addenda:

Pour ceux d’entre vous qui pensent que DataSet devrait être éliminé: En général, le modèle à utiliser est à utiliser en using ou try..finally , car vous voulez garantir que Dispose () sera appelé.

Cependant, cela devient vraiment rapide pour une collection. Par exemple, que faites-vous si l’un des appels à Dispose () émet une exception? Est-ce que vous l’avalez (ce qui est “mauvais”) pour que vous puissiez continuer à disposer de l’élément suivant?

Ou suggérez-vous d’appeler simplement myDataSet.Dispose () et d’oublier de disposer des DataTables dans myDataSet.Tables?

Voici quelques discussions expliquant pourquoi Dispose n’est pas nécessaire pour un DataSet.

Se débarrasser ou ne pas se débarrasser? :

La méthode Dispose dans DataSet existe UNIQUEMENT à cause des effets secondaires de l’inheritance – en d’autres termes, elle ne fait rien en fin de compte.

Dispose doit-il être appelé sur les objects DataTable et DataSet? comprend une explication d’un MVP:

L’espace de noms system.data (ADONET) ne contient pas de ressources non gérées. Par conséquent, il n’est pas nécessaire d’en disposer si vous ne vous êtes pas ajouté quelque chose de spécial.

Comprendre la méthode Dispose et les jeux de données? a un commentaire de l’autorité Scott Allen:

En pratique, nous éliminons rarement un DataSet parce qu’il offre peu d’avantages ”

Donc, le consensus est qu’il n’y a actuellement aucune bonne raison d’appeler Dispose sur un DataSet.

Mise à jour (1er décembre 2009):

J’aimerais modifier cette réponse et admettre que la réponse initiale était erronée.

L’parsing initiale s’applique aux objects nécessitant une finalisation – et le fait que les pratiques ne doivent pas être acceptées en surface sans une compréhension précise et approfondie existe toujours.

Cependant, il s’avère que DataSets, DataViews, DataTables suppriment la finalisation dans leurs constructeurs – c’est pourquoi appeler Dispose () sur eux ne fait explicitement rien.

Vraisemblablement, cela se produit parce qu’ils n’ont pas de ressources non gérées; Par conséquent, malgré le fait que MarshalByValueComponent prenne en compte les ressources non gérées, ces implémentations particulières ne sont pas nécessaires et peuvent donc se terminer.

(Que les auteurs .NET prennent soin de supprimer la finalisation sur les types qui occupent normalement le plus de mémoire, cela montre l’importance de cette pratique en général pour les types finalisables.)

Malgré tout, ces détails sont encore sous-documentés depuis la création du .NET Framework (il y a presque 8 ans) est assez surprenant (que vous êtes essentiellement laissé à vous-même pour filtrer les documents contradictoires et ambigus pour assembler les pièces) est parfois frustrant, mais fournit une compréhension plus complète du cadre sur lequel nous comptons tous les jours).

Après beaucoup de lecture, voici ma compréhension:

Si un object nécessite une finalisation, il pourrait occuper la mémoire plus longtemps que nécessaire – voici pourquoi: a) tout type qui définit un destructeur (ou hérite d’un type qui définit un destructeur) est considéré comme définissable; b) Lors de l’allocation (avant l’exécution du constructeur), un pointeur est placé dans la queue de finalisation. c) Un object finalisable nécessite normalement la récupération de 2 collections (au lieu de la norme 1); d) La suppression de la finalisation ne supprime pas un object de la queue de finalisation (comme indiqué par! FinalizeQueue dans SOS) Cette commande est trompeuse; Savoir quels objects se trouvent dans la queue de finalisation n’est pas utile. Il serait utile de savoir quels objects se trouvent dans la file d’attente de finalisation et qu’il rest à finaliser (existe-t-il une commande pour cela?)

La suppression de la finalisation désactive un peu dans l’en-tête de l’object, indiquant à l’exécution qu’il n’est pas nécessaire d’appeler son Finalizer (il n’est pas nécessaire de déplacer la queue FReachable). Il rest dans la queue de finalisation (et continue à être signalé par! FinalizeQueue dans SOS)

Les classes DataTable, DataSet, DataView sont toutes rootées sur MarshalByValueComponent, un object finalisable pouvant gérer (potentiellement) des ressources non managées.

  • Étant donné que DataTable, DataSet, DataView n’introduisent pas de ressources non gérées, ils suppriment la finalisation dans leurs constructeurs
  • Bien qu’il s’agisse d’un motif inhabituel, l’appelant n’a plus à se soucier d’appeler Dispose après utilisation
  • Cela, et le fait que DataTables peuvent potentiellement être partagés entre différents DataSets, est probablement la raison pour laquelle les DataSets ne se soucient pas de disposer de DataTables enfants
  • Cela signifie également que ces objects apparaîtront sous le! FinalizeQueue dans SOS
  • Cependant, ces objects doivent toujours être récupérables après une seule collection, comme leurs homologues non finalisables.

4 (nouvelles références):

Réponse originale:

Il y a beaucoup de réponses trompeuses et généralement très médiocres à ce sujet – quiconque a atterri ici doit ignorer le bruit et lire attentivement les références ci-dessous.

Dispose devrait être appelé sur tous les objects finalisables.

Les DataTables sont finalisables.

Calling Dispose accélère considérablement la récupération de la mémoire.

MarshalByValueComponent appelle GC.SuppressFinalize (this) dans son Dispose () – ignorer cela signifie qu’il faut attendre des dizaines sinon des centaines de collections Gen0 avant de récupérer la mémoire:

Avec cette compréhension de base de la finalisation, nous pouvons déjà déduire des choses très importantes:

Premièrement, les objects qui doivent être finalisés vivent plus longtemps que les objects qui ne le sont pas. En fait, ils peuvent vivre beaucoup plus longtemps. Par exemple, supposons qu’un object qui est dans gen2 doit être finalisé. La finalisation sera planifiée mais l’object est toujours dans gen2, il ne sera donc pas collecté avant que la prochaine collection gen2 ne se produise. Cela pourrait prendre beaucoup de temps et, en fait, si les choses se passent bien, cela prendra du temps, car les collections Gen2 sont coûteuses et nous voulons donc qu’elles se produisent très rarement. Les objects plus anciens nécessitant une finalisation pourraient devoir attendre des dizaines, voire des centaines de collections gen0 avant que leur espace ne soit récupéré.

Deuxièmement, les objects qui doivent être finalisés causent des dommages collatéraux. Comme les pointeurs d’object internes doivent restr valides, non seulement les objects nécessitant une finalisation directe restront en mémoire, mais tout ce à quoi l’object se réfère, directement et indirectement, restra également en mémoire. Si un grand arbre d’objects était ancré par un seul object qui nécessitait une finalisation, alors l’arbre entier pourrait persister, potentiellement pendant une longue période, comme nous venons de le voir. Il est donc important d’utiliser les finaliseurs avec parcimonie et de les placer sur des objects ayant le moins de pointeurs d’object internes possibles. Dans l’exemple d’arbre que je viens de donner, vous pouvez facilement éviter le problème en déplaçant les ressources nécessitant une finalisation vers un object distinct et en gardant une référence à cet object dans la racine de l’arborescence. Avec ce modeste changement, seul le seul object (avec un peu de chance, un petit object) persisterait et le coût de la finalisation serait réduit au minimum.

Enfin, les objects nécessitant une finalisation créent un travail pour le thread du finaliseur. Si votre processus de finalisation est complexe, le seul thread du finaliseur passera beaucoup de temps à effectuer ces étapes, ce qui peut entraîner un retard dans le travail et par conséquent, plus d’objects à attendre avant d’être finalisés. Par conséquent, il est extrêmement important que les finalisateurs travaillent le moins possible. Rappelez-vous également que bien que tous les pointeurs d’objects restnt valides pendant la finalisation, il se peut que ces pointeurs conduisent à des objects déjà finalisés et donc peu utiles. Il est généralement préférable d’éviter de suivre les pointeurs d’object dans le code de finalisation même si les pointeurs sont valides. Un chemin de code de finalisation sûr et court est le meilleur.

Prenez-le de quelqu’un qui a vu des centaines de Mo de DataTables non référencés dans Gen2: c’est extrêmement important et complètement oublié par les réponses sur ce sujet.

Les références:

1 – http://msdn.microsoft.com/en-us/library/ms973837.aspx

2 – http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage -collector-performance-using-finalizedispose-pattern.aspx

3 – http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/

Vous devez supposer qu’il fait quelque chose d’utile et appeler Dispose même s’il ne fait rien en cours. Incarnations NET Framework, il n’y a aucune garantie que cela restra comme ça dans les versions futures, conduisant à une utilisation inefficace des ressources.

Même si l’object n’a pas de ressources non managées, la suppression peut aider GC en brisant les graphiques d’object. En général, si l’object implémente IDisposable, Dispose () doit être appelé.

Que Dispose () fasse quelque chose ou non dépend de la classe donnée. Dans le cas de DataSet, l’implémentation de Dispose () est héritée de MarshalByValueComponent. Il se supprime du conteneur et appelle l’événement Disposed. Le code source est ci-dessous (démonté avec .NET Reflector):

 protected virtual void Dispose(bool disposing) { if (disposing) { lock (this) { if ((this.site != null) && (this.site.Container != null)) { this.site.Container.Remove(this); } if (this.events != null) { EventHandler handler = (EventHandler) this.events[EventDisposed]; if (handler != null) { handler(this, EventArgs.Empty); } } } } } 

Créez-vous vous-même les DataTables? Parce que l’itération à travers les enfants de n’importe quel object (comme dans DataSet.Tables) n’est généralement pas nécessaire, car c’est le travail du parent de disposer tous ses membres enfants.

En règle générale, la règle est la suivante: si vous l’avez créée et qu’elle implémente IDisposable, supprimez-la. Si vous ne l’avez PAS créé, ne le jetez PAS, c’est le travail de l’object parent. Mais chaque object peut avoir des règles spéciales, consultez la documentation.

Pour .net 3.5, il est explicitement dit “Dispose it lorsqu’elle n’utilise plus”, c’est ce que je ferais.

J’appelle disposer à tout moment qu’un object implémente IDisposeable. C’est pour une raison.

Les DataSets peuvent être de gros morceaux de mémoire. Le plus tôt ils peuvent être marqués pour le nettoyage, le mieux.

mettre à jour

Cela fait 5 ans que j’ai répondu à cette question. Je suis toujours d’accord avec ma réponse. S’il existe une méthode dispos, elle devrait être appelée lorsque vous en avez fini avec l’object. L’interface IDispose a été implémentée pour une raison.

Si votre intention ou le contexte de cette question est vraiment un nettoyage de la mémoire, vous pouvez définir les jeux de données et les tables de données de manière explicitement nulle ou utiliser le mot-clé avec utilisation et les laisser hors de scope. Dispose ne fait pas beaucoup comme Tetraneutron l’a dit plus tôt. Le GC collectera les objects de jeux de données qui ne sont plus référencés et ceux qui sont hors de scope.

Je souhaite vraiment que SO ait forcé les gens à voter pour écrire un commentaire avant de voter la réponse.

Les ensembles de données implémentent IDisposable complete MarshalByValueComponent, qui implémente IDisposable. Comme les jeux de données sont gérés, il n’ya pas de réel avantage à appeler disposer.

Essayez d’utiliser la fonction Clear (). Cela fonctionne très bien pour moi de disposer.

 DataTable dt = GetDataSchema(); //populate dt, do whatever... dt.Clear(); 

Tout d’abord, je vérifierais ce que fait Dispose avec un DataSet. Peut-être que l’utilisation du réflecteur de Redgate aidera.