Quelle est la bonne façon de libérer de la mémoire en C#
J'ai une minuterie en C# qui permet d'exécuter un code à l'intérieur de la méthode. Dans le code que j'utilise plusieurs objets temporaires.
-
Si j'ai quelque chose comme
Foo o = new Foo();
à l'intérieur de la méthode, cela signifie que chaque fois que le timer tiques, je suis en création d'un nouvel objet et une nouvelle référence à cet objet? -
Si j'ai
string foo = null
et puis je viens de mettre quelque chose de temporel dans toto, est-il le même que ci-dessus? -
Ne le garbage collector jamais supprimer l'objet et la référence du ou des objets sont continuellement créés et de rester dans la mémoire?
-
Si je viens de déclarer
Foo o;
et non point à une instance, n'est-ce pas éliminés lors de la méthode se termine? -
Si je veux m'assurer que tout est supprimé, quelle est la meilleure façon de le faire:
- avec l'aide de l'énoncé à l'intérieur de la méthode
- par l'appel de la méthode dispose à la fin
- en mettant
Foo o;
à l'extérieur de la minuterie de la méthode et simplement la cessiono = new Foo()
à l'intérieur, alors le pointeur de l'objet est supprimé après la méthode se termine, le garbage collector supprimer l'objet.
Vous devez vous connecter pour publier un commentaire.
Oui.
Si vous vous demandez si le comportement est le même, alors oui.
La mémoire utilisée par ces objets est certainement recueilli après les références sont réputés être utilisés.
Non, car aucun objet n'a été créé il n'y a aucun objet à collectionner (dispose n'est pas le bon mot).
Si la classe de l'objet implémente
IDisposable
alors vous avez certainement envie d'goulûment appelDispose
dès que possible. Leusing
mot-clé le rend cela plus facile parce qu'il appelleDispose
automatiquement dans une exception de sécurité.Autre que qu'il n'y a vraiment rien d'autre que vous devez faire, sauf à cesser d'utiliser l'objet. Si la référence est une variable locale, puis quand elle est hors de portée, il sera admissible à la collection.1 Si c'est une classe de niveau variable, alors vous pouvez avoir besoin d'attribuer
null
de la rendre admissible avant de la classe conteneur est admissible.1C'est techniquement incorrect (ou au moins un peu trompeur). Un objet peut être admissible pour la collecte à long avant qu'il passe hors de portée. Le CLR est optimisé pour recueillir la mémoire lorsqu'il détecte qu'une référence n'est plus utilisé. Dans les cas extrêmes, le CLR pouvez collecter un objet alors même que l'une de ses méthodes est toujours en cours d'exécution!
Mise à jour:
Voici un exemple qui démontre que le GC va collecter des objets, même si elles peuvent encore être étendue. Vous devez compiler une Version de construire et d'exécuter ce en dehors du débogueur.
Sur ma machine le finaliseur est exécutée alors que
SomeMethod
est toujours en cours d'exécution!this
de référence. Après que l'objet est techniquement admissible tant que le CLR peut détecter qu'il n'est pas utilisé par la suite, même si elle peut avoir des racines.Main
méthode via un simple appel du constructeur et de l'attribuer à une référence locale. Puis commencer à allouer beaucoup plus de mémoire pour déclencher un GC, mais assurez-vous de ne pas utiliser cette référence à jamais dans laMain
méthode. Vous devrez peut-être définir un destructeur de l'objet, de sorte que vous pouvez vérifier que le finaliseur a été appelé avant la référence est hors de portée. Assurez-vous de le faire fonctionner avec un Communiqué de construire en dehors du débogueur.bo
pour obtenir recueillies pour avantBegin SomeMethod
est imprimé. Je crois que cela peut être possible si la pression de la mémoire (ou l'appel àGC.Collect
) ont été effectués sur anothr fil. Mais, encore plus de plaisir test pour voir si nous pouvons obtenir en quelque sortebo
recueillies avantSomeMethod
apparaît même sur la pile. J'ai quelques idées sur la façon dont cela pourrait être réalisé, mais il entraînerait des IL la supercherie et je l'ai entièrement doute si cela est encore possible.bo.SomeMethod
. C'est fixé maintenant.callvirt
instruction qui s'exécuteSomeMethod
. Je me demande ce qui se passerait si qui ont été changé pour uncall
instruction. Lecall
instruction n'est pas un extrait de lathis
de référence lors de la prise des appels de méthode et est encore juridique IL encore lorsque vous l'utilisez sur des méthodes d'instance. Je vais essayer ce lundi quand je rentre du travail. CLR version peut avoir un impact ici depuis 4.0 gère lecall
instruction différemment.L' .NET garbage collector prend soin de tout cela pour vous.
Il est capable de déterminer quand les objets ne sont plus référencées et (éventuellement) libérer la mémoire qui a été allouée.
Objets sont admissible pour la collecte des ordures une fois qu'ils
aller hors de portéedevenir inaccessible (merci ben!). La mémoire n'est pas libérée, à moins que le garbage collector croit que vous êtes à court de mémoire.À la gestion des ressources, le garbage collector de savoir quand c'est, et vous n'avez pas besoin de faire quoi que ce soit.
Pour les ressources non managées (tels que des connexions à des bases de données ou des fichiers ouverts) le garbage collector n'a aucun moyen de savoir quelle quantité de mémoire qu'ils consomment, et c'est pourquoi vous avez besoin de libérer manuellement (à l'aide de disposer, ou mieux encore l'utilisation de bloc)
Si les objets ne sont pas libérés, soit vous avez beaucoup de mémoire et il n'est pas nécessaire, ou vous êtes maintenant une référence dans votre application, et, par conséquent, le garbage collector ne sera pas gratuit (dans le cas où vous utiliser cette référence vous avez maintenu)
Foo
variable ne sera jamais jamais prendre de la mémoire.using
déclaration appelle simplement disposer sur uneIDisposable
objet lorsqu'il la quitte, donc c'est équivalent à votre deuxième point. Les deux indiquent que vous avez terminé avec l'objet et le dire à la GC que vous êtes prêt à laisser aller de lui. L'écrasement de la seule référence à l'objet aura un effet similaire.Nous allons répondre à vos questions une par une.
Voici un bref aperçu:
Une dernière chose: Si vous déclarez
Foo foo;
sans l'affecter, vous n'avez pas à vous inquiéter de rien est une fuite. Si Toto est un type de référence, rien n'a été créé. Si Toto est un type de valeur, il est alloué sur la pile, et donc seront automatiquement nettoyés.Le garbage collector de venir nettoyer tout ce qui n'a plus de références. Sauf si vous avez les ressources non managées à l'intérieur de
Foo
, l'appel de l'élimination ou à l'aide d'une instruction using sur il ne sera pas vraiment vous aider beaucoup.Je suis assez sûr que cela s'applique, puisqu'il était encore en C#. Mais, j'ai pris un jeu en cours de conception à l'aide de XNA et nous avons passé quelques temps à parler le garbage collector pour C#. La collecte des ordures est cher, puisque vous devez vérifier si vous avez des références à l'objet que vous souhaitez collecter. Donc, le GC tente de mettre ce aussi longtemps que possible. Donc, tant que vous n'avez pas à cours de mémoire physique lorsque votre programme est allé à 700 mo, c'est peut-être le GC d'être paresseux et de ne pas se soucier pour l'instant.
Mais, si vous utilisez seulement
Foo o
en dehors de la boucle et de créer uno = new Foo()
chaque fois, tout devrait fonctionner.Comme Brian souligne le GC peut recueillir tout ce qui est inaccessible, y compris les objets qui sont toujours dans la portée et alors même que les méthodes d'instance de ces objets sont encore en cours d'exécution. considérons le code suivant:
si vous exécutez avec une version debug, avec le débogueur, ou avec la ligne spécifiée sans commentaire TestMethod ne reviendra jamais. Mais l'exécution sans un débogueur TestMethod sera de retour.