web-dev-qa-db-fra.com

Détruire les objets C #

Je suis assez nouveau pour apprendre le C # (à partir de Java & C++) et j’ai une question à propos de l’élimination manuelle des ordures: est-il possible de détruire manuellement un objet en C #? Je connais l'interface IDisposable, mais supposons que je traite avec une classe que je n'ai pas écrite et qu'elle ne l'implémente pas? Il n'aurait pas de méthode .Dispose(), de sorte que et using { } est désactivé et que .Finalize est toujours soit protected, soit private, de sorte que ce n'est pas une option non plus.

(J'essaie simplement de savoir ce qui est possible en C # dans ce cas. Je suppose que si tout le reste échoue, je pourrais hériter de la classe hypothétique ImNotDisposable afin qu'elle ne implémente IDisposable.)

25
East of Nowhere

Vous ne détruisez pas manuellement les objets .Net. C’est la raison pour laquelle être un environnement géré.

En fait, si l'objet est réellement accessible, ce qui signifie que vous avez une référence que vous pouvez utiliser pour indiquer au GC quel objet vous souhaitez détruire, la collecte de cet objet sera impossible. Le GC va (jamais} _ collecter tout objet toujours accessible.

Ce que vous pouvez faire est d'appeler GC.Collect() pour forcer une collection générale. Cependant, cela n’est presque jamais une bonne idée. 

Au lieu de cela, il est probablement préférable de simplement prétendre que tout objet qui n'utilise pas de ressources non gérées et qui n'est accessible par aucun autre objet de votre programme est immédiatement détruit. Je sais que cela n'arrive pas, mais à ce stade, l'objet n'est qu'un bloc de mémoire comme un autre; vous ne pouvez pas le récupérer et il finira par être collecté, de sorte qu'il peut aussi bien être mort pour vous.

Une dernière note sur IDisposable. Vous ne devriez l'utiliser que pour les types qui encapsulent les ressources unmanaged: éléments tels que les sockets, les connexions à une base de données, les objets gdi, etc., et la souscription occasionnelle à un événement/délégué.

26
Joel Coehoorn

Bien que vous puissiez déclencher une récupération de place (vous devez déclencher GC pour toutes les générations, car vous ne pouvez pas savoir en quelle génération se trouve l'objet finalisable), vous ne pouvez pas forcer la finalisation d'un objet particulier. Vous ne pouvez compter que sur des hypothèses concernant le fonctionnement du ramasse-miettes.

En outre, étant donné que la finalisation a lieu sur son propre thread, vous devez appeler WaitForPendingFinalizers / après avoir déclenché le garbage collection.

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();

Comme d'autres l'ont déjà fait remarquer, cela peut nuire aux performances de votre application, car le recours inutile au GC peut permettre de promouvoir des objets de courte durée autrement au sein de générations supérieures, plus coûteux à collecter et moins fréquemment.

De manière générale, une classe qui implémente un finaliseur (destructeur) et ne met pas en œuvre IDisposable est mal vue. Et tout ce qui implémente IDisposable devrait appeler sa logique de finaliseur et se supprimer de la finalisation lors de la récupération de place.

Jeff Richter a récemment publié un petit truc sympa pour recevoir une notification lorsque la récupération de place a lieu .

Un autre excellent article sur Principes de base de Garbage Collector et conseils de performance par Rico Mariani (MSFT)

7
Josh

Non, vous ne pouvez pas détruire un objet spécifique. 

Il est possible d'appeler le ramasse-miettes, qui cherchera des objets à détruire, mais ce n'est presque jamais une bonne idée.

6
Jay Bazuzi

Vous pouvez forcer le ramasse-miettes à s'exécuter après que la variable que vous voulez détruire soit hors de portée, mais vous ne voulez normalement pas le faire, car le ramasse-miettes est plus efficace s'il fait son propre travail.

Vous pouvez forcer le ramassage des ordures avec GC.Collect , mais ne le faites pas. Au cours de mes 10 années en tant que développeur .NET, je n'en ai jamais eu besoin.

4
Mark Seemann

Il n'est pas possible de détruire un objet de manière déterministe. Le CLR détermine le moment où l'objet marqué est récupéré. Cela signifie que même si vous pouvez marquer un objet pour la récupération et vous assurer que les ressources gérées et non gérées sont mises de l'ordre dans leur mise au rebut (en implémentant le modèle IDisposable), la durée réelle de libération de la mémoire revient au CLR. C’est différent du C++ où vous pouvez réellement supprimer quelque chose et le publier.

Bonne codage,

Scott

2
Scott Davies

Vous ne pouvez pas détruire manuellement un objet "comme le supprime C++". Tout ce que vous pouvez faire est simplement de fermer toutes les ressources exclusives acquises par l'objet et d'annuler toutes les références à cet objet, afin que le GC puisse le collecter également. N'appelez pas GC.Collect () par vous-même, le processus de GC est coûteux, car il doit suspendre tous les autres threads pour collecter les objets en toute sécurité, alors faites simplement confiance au GC, et il démarrera en cas de besoin.

2
bashmohandes

Supposons que vous ayez une matrice de classe et que vous ayez créé deux objets matriciels aMatrix et bMatrix. En C #, vous pouvez détruire (finaliser) manuellement un objet comme ceci:

aMatrix = NULL;

GC.Collect ();

Le ramasse-miettes remarquera que votre aMatrix est NULL et le détruira (finalisera). Que ce soit ou non une bonne idée est une autre histoire.

1
MrGuest123