D'après mon expérience, il semble que la plupart des gens vous diront qu'il n'est pas judicieux de forcer un ramassage des ordures, mais dans certains cas, où vous travaillez avec des objets volumineux qui ne sont pas toujours collectés dans la génération 0 mais où la mémoire est un problème, c'est -il ok pour forcer la collecte? Existe-t-il une meilleure pratique pour le faire?
la source
TargetOfInvocationNullException
.Regardez les choses de cette façon - est-il plus efficace de jeter les ordures de la cuisine lorsque la poubelle est à 10% ou de la laisser se remplir avant de la sortir?
En ne le laissant pas se remplir, vous perdez votre temps à aller et à revenir de la poubelle à l'extérieur. Ceci est analogue à ce qui se passe lorsque le thread GC s'exécute - tous les threads gérés sont suspendus pendant son exécution. Et si je ne me trompe pas, le thread GC peut être partagé entre plusieurs AppDomains, de sorte que le garbage collection les affecte tous.
Bien sûr, vous pourriez rencontrer une situation où vous n'ajouterez rien à la poubelle de sitôt - par exemple, si vous prévoyez de prendre des vacances. Ensuite, ce serait une bonne idée de jeter les ordures avant de sortir.
Cela PEUT être une fois que forcer un GC peut aider - si votre programme est inactif, la mémoire utilisée n'est pas récupérée car il n'y a pas d'allocations.
la source
La meilleure pratique consiste à ne pas forcer un garbage collection dans la plupart des cas. (Tous les systèmes sur lesquels j'ai travaillé et qui avaient forcé le ramassage des ordures, avaient des problèmes de soulignement qui, s'ils étaient résolus, auraient éliminé le besoin de forcer le ramassage des ordures et accéléré considérablement le système.)
Il existe quelques cas où vous en savez plus sur l'utilisation de la mémoire que le ramasse-miettes. Il est peu probable que cela soit vrai dans une application multi-utilisateur ou un service qui répond à plusieurs demandes à la fois.
Cependant, dans certains traitements par lots, vous en savez plus que le GC. Par exemple, considérez une application qui.
Vous pourrez peut- être faire un cas (après avoir testé minutieusement) que vous devez forcer un garbage collection complet après avoir traité chaque fichier.
Un autre cas est un service qui se réveille toutes les quelques minutes pour traiter certains éléments et ne conserve aucun état pendant son sommeil . Alors forcer une collection complète juste avant d'aller dormir peut être utile.
Je préférerais avoir une API de ramasse-miettes quand je pourrais lui donner des conseils sur ce type de chose sans avoir à forcer moi-même un GC.
Voir aussi " Les morceaux de performance de Rico Mariani "
la source
Je pense que l'exemple donné par Rico Mariani était bon: il peut être approprié de déclencher un GC s'il y a un changement significatif dans l'état de l'application. Par exemple, dans un éditeur de document, il peut être correct de déclencher un GC lorsqu'un document est fermé.
la source
Il existe peu de directives générales en matière de programmation qui soient absolues. La moitié du temps, quand quelqu'un dit «vous faites mal», il ne fait que jaillir une certaine quantité de dogme. En C, c'était la peur de choses comme le code ou les threads qui s'auto-modifiaient, dans les langages GC, cela forçait le GC ou empêchait le GC de fonctionner.
Comme c'est le cas avec la plupart des directives et de bonnes règles empiriques (et de bonnes pratiques de conception), il existe de rares occasions où il est logique de contourner la norme établie. Vous devez être très sûr de bien comprendre le cas, que votre cas nécessite vraiment l'abrogation de la pratique courante et que vous comprenez les risques et les effets secondaires que vous pouvez causer. Mais il existe de tels cas.
Les problèmes de programmation sont très variés et nécessitent une approche flexible. J'ai vu des cas où il est logique de bloquer GC dans des langages récupérés et des endroits où il est logique de le déclencher plutôt que d'attendre qu'il se produise naturellement. 95% du temps, l'un ou l'autre signifierait que le problème n'a pas été abordé correctement. Mais 1 fois sur 20, il y a probablement un argument valable à faire pour cela.
la source
J'ai appris à ne pas essayer de déjouer le ramassage des ordures. Cela dit, je m'en tiens simplement à l'utilisation de
using
mots-clés lorsque je traite des ressources non gérées telles que les E / S de fichiers ou les connexions à la base de données.la source
Je ne sais pas si c'est une bonne pratique, mais lorsque je travaille avec de grandes quantités d'images en boucle (c'est-à-dire en créant et en supprimant beaucoup d'objets Graphics / Image / Bitmap), je laisse régulièrement GC.Collect.
Je pense avoir lu quelque part que le GC ne fonctionne que lorsque le programme est (principalement) inactif, et non au milieu d'une boucle intensive, ce qui pourrait ressembler à un domaine où le GC manuel pourrait avoir un sens.
la source
Un cas que j'ai récemment rencontré et qui nécessitait des appels manuels
GC.Collect()
était lorsque je travaillais avec de grands objets C ++ qui étaient enveloppés dans de petits objets C ++ gérés, qui à leur tour étaient accessibles à partir de C #.Le garbage collector n'a jamais été appelé car la quantité de mémoire gérée utilisée était négligeable, mais la quantité de mémoire non gérée utilisée était énorme. L'appel manuel
Dispose()
des objets nécessiterait que je surveille moi-même quand les objets ne sont plus nécessaires, tandis que l'appelGC.Collect()
nettoiera tous les objets qui ne sont plus référencés .....la source
GC.AddMemoryPressure (ApproximateSizeOfUnmanagedResource)
le constructeur et plus tardGC.RemoveMemoryPressure(addedSize)
le finaliseur. De cette façon, le garbage collector s'exécutera automatiquement, en tenant compte de la taille des structures non gérées qui pourraient être collectées. stackoverflow.com/questions/1149181/…Je pense que vous avez déjà énuméré la meilleure pratique et c'est de NE PAS l'utiliser sauf VRAIMENT nécessaire. Je recommanderais fortement d'examiner votre code plus en détail, en utilisant éventuellement des outils de profilage si nécessaire pour répondre d'abord à ces questions.
la source
Supposons que votre programme n'ait pas de fuite de mémoire, que les objets s'accumulent et ne puissent pas être GC-ed dans Gen 0 parce que: 1) Ils sont référencés pendant longtemps alors entrez dans Gen1 & Gen2; 2) Ce sont des objets volumineux (> 80 Ko), alors entrez dans LOH (Large Object Heap). Et LOH ne fait pas de compactage comme dans Gen0, Gen1 et Gen2.
Vérifiez le compteur de performances de ".NET Memory" vous pouvez voir que le problème 1) n'est vraiment pas un problème. En règle générale, tous les 10 GC Gen0 déclenchent 1 GC Gen1 et tous les 10 GC Gen1 déclenchent 1 GC Gen2. Théoriquement, GC1 et GC2 ne peuvent jamais être GC-ed s'il n'y a pas de pression sur GC0 (si l'utilisation de la mémoire du programme est vraiment câblée). Cela ne m'arrive jamais.
Pour le problème 2), vous pouvez vérifier le compteur de performances «.NET Memory» pour vérifier si LOH est gonflé. Si c'est vraiment un problème avec votre problème, vous pouvez peut-être créer un grand pool d'objets comme le suggère ce blog http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx .
la source
Les grands objets sont alloués sur LOH (grand tas d'objets), pas sur la génération 0. Si vous dites qu'ils ne sont pas récupérés avec la génération 0, vous avez raison. Je crois qu'ils ne sont collectés que lorsque le cycle complet du GC (générations 0, 1 et 2) se produit.
Cela étant dit, je crois que, de l'autre côté, GC ajustera et collectera la mémoire de manière plus agressive lorsque vous travaillez avec de gros objets et que la pression de la mémoire augmente.
Il est difficile de dire s'il faut collecter ou non et dans quelles circonstances. J'avais l'habitude de faire GC.Collect () après avoir supprimé les fenêtres / formulaires de dialogue avec de nombreux contrôles, etc. grands objets évidemment), mais n'a en fait pas remarqué d'effets positifs ou négatifs sur le long terme.
la source
Je voudrais ajouter que: L'appel de GC.Collect () (+ WaitForPendingFinalizers ()) est une partie de l'histoire. Comme mentionné à juste titre par d'autres, GC.COllect () est une collection non déterministe et est laissée à la discrétion du GC lui-même (CLR). Même si vous ajoutez un appel à WaitForPendingFinalizers, il peut ne pas être déterministe. Prenez le code de ce lien msdn et exécutez le code avec l'itération de la boucle d'objet comme 1 ou 2. Vous trouverez ce que signifie non déterministe (définir un point de rupture dans le destructeur de l'objet). Précisément, le destructeur n'est pas appelé quand il y avait juste 1 (ou 2) objets persistants par Wait .. (). [Citation reqd.]
Si votre code traite des ressources non gérées (ex: descripteurs de fichiers externes), vous devez implémenter des destructeurs (ou finaliseurs).
Voici un exemple intéressant:
Remarque : Si vous avez déjà essayé l'exemple ci-dessus à partir de MSDN, le code suivant va effacer l'air.
Je suggère d'analyser d'abord ce que pourrait être la sortie, puis de l'exécuter, puis de lire la raison ci-dessous:
{Le destructeur n'est appelé implicitement qu'une fois le programme terminé. } Afin de nettoyer l'objet de manière déterministe, il faut implémenter IDisposable et faire un appel explicite à Dispose (). Voilà l'essence! :)
la source
Une dernière chose, déclencher explicitement GC Collect ne peut PAS améliorer les performances de votre programme. Il est tout à fait possible d'aggraver les choses.
Le .NET GC est bien conçu et réglé pour être adaptatif, ce qui signifie qu'il peut ajuster le seuil GC0 / 1/2 en fonction de «l'habitude» d'utilisation de la mémoire de votre programme. Ainsi, il sera adapté à votre programme après un certain temps d'exécution. Une fois que vous appelez explicitement GC.Collect, les seuils seront réinitialisés! Et le .NET doit prendre du temps pour s'adapter à nouveau à «l'habitude» de votre programme.
Ma suggestion est toujours de faire confiance à .NET GC. Tout problème de mémoire fait surface, vérifiez le compteur de performances ".NET Memory" et diagnostiquez mon propre code.
la source
Suggestion: ne mettez pas en œuvre ceci ou quoi que ce soit en cas de doute. Réévaluez lorsque les faits sont connus, puis effectuez des tests de performance avant / après pour vérifier.
la source
À mon humble avis, cela revient à dire "Si vous pouvez prouver que votre programme n'aura jamais de bogues à l'avenir, alors allez-y ..."
En toute sincérité, forcer le GC est utile à des fins de débogage / test. Si vous sentez que vous devez le faire à un autre moment, alors soit vous vous trompez, soit votre programme a été mal construit. Quoi qu'il en soit, la solution n'est pas de forcer le GC ...
la source