Quand est-il acceptable d'appeler GC.Recueillir?
Le conseiller général est que vous ne devez pas appeler GC.Collect
à partir de votre code, mais ce sont les exceptions à cette règle?
Je ne peux que penser à quelques cas très spécifiques où il peut faire sens pour forcer un garbage collection.
Un exemple qui vient à l'esprit est un service qui se réveille à intervalles, l'exécution de certaines tâches, et puis dort pendant une longue période. Dans ce cas, il peut être une bonne idée de forcer un collecter pour empêcher le bientôt-à-être-processus inactif à partir de maintenant sur plus de mémoire que nécessaire.
Y a d'autres cas où il est acceptable d'appel GC.Collect
?
- Double Possible de les Meilleures Pratiques pour Forcer la Collecte des Ordures en C#
Vous devez vous connecter pour publier un commentaire.
Si vous avez de bonnes raisons de croire qu'un important ensemble d'objets - en particulier ceux que vous soupçonnez d'être dans les générations 1 et 2 sont maintenant admissibles pour la collecte des ordures, et qui maintenant serait un bon moment pour recueillir en termes de performances de petite frappe.
Un bon exemple de ceci est que si vous avez juste fermé une grande forme. Vous savez que tous les contrôles de l'INTERFACE utilisateur peut maintenant être nettoyée, et une très courte pause que le formulaire est fermé ne sera probablement pas perceptible pour l'utilisateur.
Mise à JOUR 2.7.2018
Comme de .NET 4.5 - il y a
GCLatencyMode.LowLatency
etGCLatencyMode.SustainedLowLatency
. Lors de la saisie et laissant l'autre de ces modes, il est recommandé que vous forcez un full GC avecGC.Collect(2, GCCollectionMode.Forced)
.Comme de .NET 4.6 - il est le
GC.TryStartNoGCRegion
méthode (utilisée pour définir la valeur en lecture seuleGCLatencyMode.NoGCRegion
). Cela peut, d'effectuer un blocage complet de collecte des ordures dans une tentative pour libérer suffisamment de mémoire, mais étant donné que nous sommes en interdisant GC pour une période, je dirais que c'est aussi une bonne idée d'effectuer des GC avant et après.Source: Microsoft ingénieur Ben Watson: Écrit Haute Performance .NET Code, 2e Ed. 2018.
Voir:
GC.Collect
vous êtes essentiellement en disant que le garbage collector que vous savez mieux que pour un changement. Pourquoi vous n'aimez pas l'exemple?GC.Collect()
: j'ai fait un traitement par lot des images, lorsque je charge une image, la redimensionner pour deux tailles d'images et de les enregistrer sur le disque: Même avec l'aide deusing
-états autour de tous lesImage
-les instances de la GC a fallu plusieurs secondes pour effacer les vieux objets --> >500 MO de RAM "unneccessarly" utilisé, comme le traitement réel de remplissage est-il que rapide --> après l'appel deGC.Collect()
après chaque image traitée n'a pas ralenti le processus de la malformation, mais l'utilisation de la RAM est stable à quelques mo...- Je utiliser
GC.Collect
seulement lors de l'écriture brut/performance profiler bancs d'essai; c'est à dire que j'ai deux (ou plus) des blocs de code pour tester quelque chose comme:De sorte que
TestA()
etTestB()
exécuter avec comme état similaire que possible - c'est à direTestB()
ne pas obtenir martelé juste parce queTestA
gauche, il est très proche du point de basculement.Un exemple classique serait une simple console exe (un
Main
méthode de tri-assez pour être posté ici par exemple), qui montre la différence entre la boucle de concaténation de chaîne etStringBuilder
.Si j'ai besoin de quelque chose de précis, alors ce serait complètement indépendant de tests - mais souvent c'est suffisant si nous voulons juste de réduire (ou de normaliser) le GC pendant les tests à faire une bonne impression pour le comportement.
Au cours de la production de code? Je n'ai pas encore l'utiliser ;-p
La meilleure pratique est de ne pas forcer une collecte des ordures dans la plupart des cas. (Chaque système, j'ai travaillé sur de qui avait forcé la collecte des poubelles, avait en soulignant les problèmes qui, si elle est résolue aurait supprimé le besoin de forcé la collecte des ordures, et accéléré le système grandement.)
Il y a un quelques cas quand vous en savoir plus sur l'utilisation de la mémoire alors que le garbage collector ne. C'est peu probable dans un multi-utilisateur de l'application ou un service qui répond à plus d'une demande à la fois.
Toutefois, dans certains lot de traitement de type vous ne savez plus que le GC. E. g. imaginez une application.
Vous peut être en mesure de faire une affaire (après mûre) les tests que vous devez forcer un plein de collecte des ordures après avoir traiter chaque fichier.
Un autre cas est un service qui se réveille toutes les quelques minutes pour traiter de certains éléments, et ne pas garder en l'état pendant qu'il est endormi. Alors forcement une collection complète juste avant d'aller dormir peut la peine.
Je préférerais avoir un garbage collection API quand j'ai pu lui donner des conseils sur ce type de chose, sans avoir à forcer un GC mon auto.
Voir aussi "Rico Mariani Performances de Friandises"
Un cas est lorsque vous essayez de l'unité de test de code qui utilise WeakReference.
Dans les grandes 24/7 ou 24/6 systèmes-systèmes qui réagissent aux messages, les requêtes RPC ou que l'interrogation d'une base de données ou un processus continu -- il est utile d'avoir un moyen d'identifier les fuites de mémoire. Pour cela, j'ai tendance à ajouter un mécanisme pour l'application de suspendre temporairement le traitement et ensuite effectuer la collecte des ordures. Cela permet de mettre le système dans un état de repos où la mémoire restante est soit légitimement longue durée de vie de la mémoire (caches, de configuration, &c.) ou bien est - 'fuite' (objets qui ne sont pas prévus ou souhaitée pour être enracinée mais sont en réalité).
Avoir ce mécanisme rend beaucoup plus facile pour le profil de l'utilisation de la mémoire que les rapports ne seront pas obscurcie par des bruits de traitement actif.
Pour être sûr que vous obtenez toutes les ordures, vous devez effectuer deux collections:
Comme la première collection sera la cause de tous les objets avec les finaliseurs être finalisé (mais pas réellement de déchets collecter ces objets). La deuxième GC ordures recueillir ces finalisé objets.
Comme une fragmentation de la mémoire de la solution.
J'ai de la mémoire des exceptions lors de l'écriture d'un grand nombre de données dans un flux de mémoire (lecture d'un flux réseau). Les données ont été écrites en 8K morceaux. Après avoir atteint 128M il n'y a d'exception, même si il y avait beaucoup de mémoire disponible (mais il a été fragmenté). L'appel de GC.Collect() a résolu le problème. J'ai été en mesure de traiter plus de 1G après le correctif.
Vous pouvez appeler GC.Collect() lorsque vous savez quelque chose sur la nature de l'application sur le garbage collector n'est pas. Il est tentant de penser que, comme l'auteur, c'est très probable. Cependant, la vérité est que le GC montants pour un assez bien écrit et testé système expert, et il est rare que vous savez quelque chose sur le code bas-niveau des chemins qu'il n'a pas.
Le meilleur exemple que je peux penser de l'endroit où vous pourriez avoir quelques informations supplémentaires est une application que les cycles entre les périodes d'inactivité et de la période très chargée. Vous voulez le meilleur rendement possible pour les périodes de pointe, et donc voulez utiliser le temps d'attente pour faire un peu de ménage en place.
Cependant, la plupart du temps, le GC est assez intelligent pour faire cela de toute façon.
Ont un coup d'oeil à cet article par Rico Mariani. Il donne deux règles quand appeler le GC.Collecter (règle 1: "Ne pas"):
Quand appeler le GC.Collect()
Je faisais des tests de performance sur le tableau et de liste:
et j'ai eu
OutOfMemoryException
dans GetSomeNumbers_Enumerable_Range méthode, la seule solution est de libérer la mémoire par:Dans votre exemple, je pense que l'appel de GC.Percevoir n'est pas la question, mais il y a un problème de conception.
Si vous allez à se réveiller à intervalles réguliers (des temps), alors votre programme doit être conçu pour une exécution unique (effectuer la tâche une fois) et ensuite mettre fin. Ensuite, vous définissez le programme comme une tâche planifiée pour s'exécuter à intervalles réguliers.
De cette façon, vous n'avez pas à vous préoccuper de l'appel de GC.Recueillir, (ce qui devrait rarement si jamais le faire).
Cela étant dit, Rico Mariani a un super blog sur ce sujet, qui peut être trouvé ici:
http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx
Une instance où il est presque nécessaire de faire appel à GC.Collect() est pour l'automatisation de Microsoft Office grâce à l'Interopérabilité. COM objets pour le Bureau n'aime pas pour libérer automatiquement et peut entraîner, dans le cas de l'Office produit en prenant de très grandes quantités de mémoire. Je ne suis pas sûr si c'est un problème ou pas. Il y a beaucoup de messages sur ce sujet autour de l'internet, donc je ne vais pas trop entrer dans les détails.
Lors de la programmation de l'aide de l'Interopérabilité, chaque objet doit être manuellement publié, généralement, bien que l'utilisation du Maréchal.ReleseComObject(). En outre, l'appel de la Collecte des Ordures manuellement peut aider à "nettoyer" un peu. Appeler le code suivant lorsque vous avez terminé avec l'Interopérabilité des objets semble aider un peu:
Dans mon expérience personnelle, en utilisant une combinaison de ReleaseComObject et manuellement l'appel de la collecte des ordures grandement réduit l'utilisation de la mémoire de produits Office, plus particulièrement Excel.
Utile, un endroit pour appeler à la GC.Collect() est une unité de test lorsque vous souhaitez vérifier que vous n'êtes pas la création d'une fuite de mémoire (e. g. si vous faites quelque chose avec WeakReferences ou ConditionalWeakTable, du code généré dynamiquement, etc).
Par exemple, j'ai un peu de tests comme:
Il pourrait être soutenu que l'utilisation de WeakReferences est un problème en soi, mais il semble que si vous créez un système qui repose sur un tel comportement, puis l'appel de GC.Collect() est un bon moyen de vérifier un tel code.
La réponse courte est: jamais!!!!
Il y a des situations où il vaut mieux prévenir que guérir.
Ici est un exemple de situation.
Il est possible de créer un non géré une DLL en C# à l'aide de l'IL réécrit (parce qu'il y a des situations où cela est nécessaire).
Maintenant, supposons, par exemple, la DLL crée un tableau d'octets au niveau de la classe - parce que beaucoup de fonctions exportées ont besoin d'accéder à ces. Ce qui se passe lorsque la DLL est déchargée? Est le garbage collector qui est automatiquement appelé à ce point? Je ne sais pas, mais étant non géré DLL il est tout à fait possible de le GC n'est pas appelé. Et ce serait un gros problème si elle n'était pas appelée. Lorsque la DLL est déchargée aussi être le garbage collector - alors, qui va être responsable de la collecte des éventuels déchets et comment pourraient-ils le faire? Préférable de faire appel à C#'s garbage collector. Ont une fonction de nettoyage (disponible à la DLL du client) où le niveau de la classe de variables sont null et le garbage collector appelé.
Mieux sécurisé que désolé.
je ne suis vraiment pas sur.
Je travaille depuis 7 ans sur un Serveur d'Application. Nos grandes installations, prendre de 24 GO de Ram. Sa hautement Multithread, et TOUS les appels pour le GC.Collect() a couru dans l'énormité des problèmes de performances.
De nombreux Composants tiers utilisés GC.Collect() quand ils ont pensé qu'il était plus intelligente à faire de ce droit maintenant.
Ainsi, un simple tas de Excel-Rapports bloqué le Serveur d'Application pour tous les threads plusieurs fois par minute.
Nous avons eu à refactoriser tous les 3e Partie des Composants afin de supprimer la GC.Collect() appels, et tout a bien fonctionné après avoir fait cela.
Mais je suis en cours d'exécution Serveurs sur Win32, et ici j'ai commencé à prendre de l'utilisation lourde de la GC.Collect() après l'obtention d'une OutOfMemoryException.
Mais je suis aussi assez pas sur, car j'ai souvent remarqué, quand je reçois un OOM sur 32 Bits, et j'ai réessayer pour exécuter la même Opération encore une fois, sans faire appel GC.Collect(), cela a bien fonctionné.
Une chose que je me demande est le OOM Exception de lui-même...
Si j'aurais écrit la .Net Framework, et je ne peux pas alloue un bloc de mémoire, je voudrais utiliser GC.Collect(), la défragmentation de la mémoire (??), essayez de nouveau, et si je peux pas trouver un bloc de mémoire disponible, alors je voudrais jeter le OOM-Exception.
Ou au moins de faire ce comportement comme option configurable, en raison des inconvénients de la problème de performance avec la GC.Collecter.
Maintenant, j'ai beaucoup de ce type de code dans mon appli pour "résoudre" le problème:
(À noter que le Thread.Sleep() le comportement est vraiment une Application apecific comportement, parce que nous avons un ORM Service de mise en Cache, et le service prend un certain temps à la libération de tous les objets mis en cache, si la RAM dépasse certaines valeurs prédéfinies. donc, il attend quelques secondes la première fois, et a augmenté le temps d'attente de chaque occurence de OOM.)
GC.Collect
. Depuis, il dispose d'une application à l'échelle d'effet que la demande devrait le faire (si).If i would have written the .Net Framework, and i can't alloc a memory block, i would use GC.Collect(),
- Je pense qu'ils sont déjà en train de le cette - j'ai vu des indications que l'un des internes GC déclencheurs, certaines pannes d'allouer de la mémoire.Scott Holden l'entrée de blog sur les cas où (et quand) appel GC.Recueillir est spécifique à la .NET Compact Framework, mais les règles qui s'appliquent généralement à tous gérés de développement.
Vous devriez essayer d'éviter d'utiliser des GC.Collect() depuis son très cher. Voici un exemple:
RÉSULTAT DU TEST: UTILISATION DE L'UC 12%
Lorsque vous modifiez à présent:
RÉSULTAT DU TEST: UTILISATION DU PROCESSEUR DE 2 À 3%
Ce n'est pas la question, mais pour XSLT transforme en .NET (XSLCompiledTranform) alors vous n'avez pas le choix. Un autre candidat est le contrôle MSHTML.
Si vous utilisez une version de .net inférieur à 4,5, la collecte manuelle est peut-être inévitable (surtout si vous avez affaire avec beaucoup de "grands objets").
ce lien explique pourquoi:
https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/
une bonne raison pour appeler GC est sur les petits BRAS ordinateurs avec peu de mémoire, comme le Raspberry PI (en cours d'exécution avec mono).
Si non alloué de la mémoire des fragments d'utiliser trop de la RAM du système, puis le système d'exploitation Linux peut se instable.
J'ai une application dans laquelle j'ai appeler GC chaque seconde (!) pour se débarrasser des problèmes de débordement de la mémoire.
Une autre bonne solution est de disposer d'objets lorsqu'ils ne sont plus nécessaires. Malheureusement, ce n'est pas si facile, dans de nombreux cas.
Car il y a des tas de Petits objets(SOH) et des tas d'objets Volumineux(LOH)
Nous pouvons appeler GC.Collect() pour effacer de l'objet de référence dans les SOP, et déplacez vécu de l'objet de la prochaine génération.
Dans .net4.5, nous pouvons aussi compact LOH en utilisant largeobjectheapcompactionmode