Le conseil général est de ne pas appeler à GC.Collect
partir de votre code, mais quelles sont les exceptions à cette règle?
Je ne peux penser qu'à quelques cas très spécifiques où il peut être judicieux de forcer un ramassage des ordures.
Un exemple qui me vient à l'esprit est un service, qui se réveille à intervalles réguliers, effectue une tâche, puis dort pendant une longue période. Dans ce cas, il peut être judicieux de forcer une collecte pour empêcher le processus sur le point d'être inactif de conserver plus de mémoire que nécessaire.
Y a-t-il d'autres cas où il est acceptable d'appeler GC.Collect
?
c#
.net
garbage-collection
Brian Rasmussen
la source
la source
Réponses:
Si vous avez de bonnes raisons de croire qu'un ensemble important d'objets - en particulier ceux que vous pensez appartenir aux générations 1 et 2 - sont désormais éligibles pour le ramasse-miettes, et que ce serait maintenant le moment opportun pour collecter en termes de faible impact sur les performances .
Un bon exemple de ceci est si vous venez de fermer un grand formulaire. Vous savez que tous les contrôles de l'interface utilisateur peuvent désormais être récupérés, et une très courte pause lorsque le formulaire est fermé ne sera probablement pas perceptible pour l'utilisateur.
MISE À JOUR 2.7.2018
À partir de .NET 4.5 - il existe
GCLatencyMode.LowLatency
etGCLatencyMode.SustainedLowLatency
. Lors de l'entrée et de la sortie de l'un de ces modes, il est recommandé de forcer un GC complet avecGC.Collect(2, GCCollectionMode.Forced)
.À partir de .NET 4.6 - il existe la
GC.TryStartNoGCRegion
méthode (utilisée pour définir la valeur en lecture seuleGCLatencyMode.NoGCRegion
). Cela peut lui-même, effectuer un garbage collection de blocage complet dans le but de libérer suffisamment de mémoire, mais étant donné que nous interdisons GC pendant un certain temps, je dirais que c'est également une bonne idée d'effectuer un GC complet avant et après.Source: Ben Watson, ingénieur Microsoft: Writing High-Performance .NET Code , 2nd Ed. 2018.
Voir:
la source
GC.Collect
vous dites essentiellement au ramasse-miettes que vous savez mieux que ça pour changer. Pourquoi n'aimez-vous pas l'exemple?GC.Collect()
demandera que le GC effectue une collecte complète . Si vous savez que vous venez de rendre éligibles à la collecte des ordures de nombreux objets de longue durée de vie et que vous pensez que l'utilisateur est moins susceptible de remarquer une légère pause maintenant que plus tard, il semble tout à fait raisonnable de penser que maintenant c'est mieux il est temps d'inviter une collection plutôt que de la laisser arriver plus tard.Je n'utilise
GC.Collect
que lors de l'écriture de bancs d'essai de performances / profileurs bruts; c'est-à-dire que j'ai deux (ou plus) blocs de code à tester - quelque chose comme:Donc,
TestA()
etTestB()
courir avec un état aussi similaire que possible - c'est-à-direTestB()
ne pas être martelé simplement parceTestA
qu'il l'a laissé très proche du point de basculement.Un exemple classique serait un simple exe de console (une
Main
méthode suffisamment triée pour être publiée ici par exemple), qui montre la différence entre la concaténation de chaînes en boucle etStringBuilder
.Si j'ai besoin de quelque chose de précis, alors ce serait deux tests complètement indépendants - mais souvent cela suffit si nous voulons simplement minimiser (ou normaliser) le GC pendant les tests pour avoir une idée approximative du comportement.
Pendant le code de production? Je ne l'ai pas encore utilisé ;-p
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 pouvez ê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
Un cas est lorsque vous essayez de tester un code qui utilise WeakReference .
la source
Dans les grands systèmes 24/7 ou 24/6 - des systèmes qui réagissent aux messages, aux demandes RPC ou qui interrogent une base de données ou un processus en continu - il est utile de disposer d'un moyen d'identifier les fuites de mémoire. Pour cela, j'ai tendance à ajouter un mécanisme à l'application pour suspendre temporairement tout traitement, puis effectuer un garbage collection complet. Cela met le système dans un état de repos où la mémoire restante est soit une mémoire légitimement longue durée (caches, configuration, etc.), soit une `` fuite '' (objets qui ne sont pas attendus ou dont on ne souhaite pas enraciner mais qui le sont en réalité).
Ce mécanisme facilite grandement le profil de l'utilisation de la mémoire, car les rapports ne seront pas assombri par le bruit du traitement actif.
Pour être sûr d'obtenir toutes les ordures, vous devez effectuer deux collectes:
Comme la première collecte entraînera la finalisation de tous les objets avec des finaliseurs (mais pas réellement de ramasser ces objets). Le second GC récupérera ces objets finalisés.
la source
Vous pouvez appeler GC.Collect () lorsque vous savez quelque chose sur la nature de l'application que le garbage collector ne sait pas. Il est tentant de penser que, en tant qu'auteur, c'est très probable. Cependant, la vérité est que le GC est un système expert assez bien écrit et testé, et il est rare que vous sachiez quelque chose sur les chemins de code de bas niveau qu'il ne connaît pas.
Le meilleur exemple auquel je puisse penser où vous pourriez avoir des informations supplémentaires est une application qui alterne entre les périodes d'inactivité et les périodes très occupées. Vous voulez les meilleures performances possibles pour les périodes de pointe et vous voulez donc utiliser le temps d'inactivité pour effectuer un certain nettoyage.
Cependant, la plupart du temps, le GC est assez intelligent pour le faire de toute façon.
la source
En tant que solution de fragmentation de la mémoire. Je sortais des exceptions de mémoire en écrivant beaucoup de données dans un flux mémoire (lecture à partir d'un flux réseau). Les données ont été écrites en blocs de 8 Ko. Après avoir atteint 128 Mo, il y avait une exception même s'il y avait beaucoup de mémoire disponible (mais elle était fragmentée). L'appel de GC.Collect () a résolu le problème. J'ai pu gérer plus de 1G après le correctif.
la source
Jetez un œil à cet article de Rico Mariani. Il donne deux règles pour appeler GC.Collect (la règle 1 est: "Ne pas"):
Quand appeler GC.Collect ()
la source
Une instance où il est presque nécessaire d'appeler GC.Collect () est lors de l'automatisation de Microsoft Office via Interop. Les objets COM pour Office n'aiment pas être libérés automatiquement et peuvent entraîner des instances du produit Office occupant de très grandes quantités de mémoire. Je ne sais pas si c'est un problème ou par conception. Il y a beaucoup de messages sur ce sujet sur Internet, donc je n'entrerai pas trop dans les détails.
Lors de la programmation à l'aide d'Interop, chaque objet COM doit être libéré manuellement, généralement via l'utilisation de Marshal.ReleseComObject (). De plus, appeler manuellement Garbage Collection peut aider à "nettoyer" un peu. L'appel du code suivant lorsque vous avez terminé avec les objets Interop semble aider un peu:
D'après mon expérience personnelle, l'utilisation d'une combinaison de ReleaseComObject et d'un appel manuel du garbage collection réduit considérablement l'utilisation de la mémoire des produits Office, en particulier Excel.
la source
Je faisais des tests de performances sur le tableau et la liste:
et j'ai obtenu
OutOfMemoryException
dans la méthode GetSomeNumbers_Enumerable_Range la seule solution de contournement est de désallouer la mémoire en:la source
Dans votre exemple, je pense qu'appeler GC.Collect n'est pas le problème, mais plutôt un problème de conception.
Si vous prévoyez de vous réveiller à intervalles (horaires définis), votre programme doit être conçu pour une seule exécution (effectuer la tâche une fois), puis se terminer. Ensuite, vous configurez le programme en tant que tâche planifiée à exécuter aux intervalles planifiés.
De cette façon, vous n'avez pas à vous soucier d'appeler GC.Collect, (ce que vous devriez rarement, voire jamais, faire).
Cela étant dit, Rico Mariani a un excellent article de blog sur ce sujet, que vous pouvez trouver ici:
http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx
la source
Un endroit utile pour appeler GC.Collect () est dans un test unitaire lorsque vous voulez vérifier que vous ne créez pas une fuite de mémoire (par exemple si vous faites quelque chose avec WeakReferences ou ConditionalWeakTable, code généré dynamiquement, etc.).
Par exemple, j'ai quelques tests comme:
On pourrait soutenir 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, appeler GC.Collect () est un bon moyen de vérifier ce code.
la source
L' entrée de blog de Scott Holden sur quand (et quand ne pas) appeler GC.Collect est spécifique au .NET Compact Framework , mais les règles s'appliquent généralement à tout développement géré.
la source
La réponse courte est: jamais!
la source
la source
Il y a des situations où il vaut mieux prévenir que guérir.
Voici une situation.
Il est possible de créer une DLL non gérée en C # à l'aide de réécritures IL (car dans certaines situations, cela est nécessaire).
Supposons maintenant, par exemple, que la DLL crée un tableau d'octets au niveau de la classe - car la plupart des fonctions exportées doivent y accéder. Que se passe-t-il lorsque la DLL est déchargée? Le garbage collector est-il automatiquement appelé à ce stade? Je ne sais pas, mais étant une DLL non gérée, il est tout à fait possible que le GC ne soit pas appelé. Et ce serait un gros problème s'il n'était pas appelé. Lorsque la DLL est déchargée, il en sera de même pour le ramasse-miettes - alors qui sera responsable de la collecte des éventuels déchets et comment le ferait-il? Mieux vaut utiliser le ramasse-miettes de C #. Avoir une fonction de nettoyage (disponible pour le client DLL) où les variables de niveau de classe sont définies sur null et le garbage collector appelé.
Mieux vaut prévenir que guérir.
la source
je suis encore assez incertain à ce sujet. Je travaille depuis 7 ans sur un serveur d'application. Nos plus grandes installations utilisent 24 Go de RAM. Ses appels extrêmement multithread et ALL pour GC.Collect () se sont heurtés à des problèmes de performances vraiment terribles.
De nombreux composants tiers ont utilisé GC.Collect () alors qu'ils pensaient que c'était intelligent de le faire maintenant. Ainsi, un simple tas de rapports Excel bloquait le serveur d'applications pour tous les threads plusieurs fois par minute.
Nous avons dû refactoriser tous les composants tiers afin de supprimer les appels GC.Collect (), et tout a bien fonctionné après cela.
Mais j'utilise également des serveurs sur Win32, et ici j'ai commencé à utiliser beaucoup GC.Collect () après avoir obtenu une OutOfMemoryException.
Mais je suis également assez incertain à ce sujet, car j'ai souvent remarqué que lorsque j'obtiens un MOO sur 32 bits et que je réessaye d'exécuter à nouveau la même opération, sans appeler GC.Collect (), cela fonctionnait très bien.
Une chose que je me demande est l'exception OOM elle-même ... Si j'avais écrit le .Net Framework et que je ne peux pas allouer un bloc de mémoire, j'utiliserais GC.Collect (), défragmenter la mémoire (??), réessayer , et si je ne trouve toujours pas un bloc de mémoire libre, alors je lancerais l'exception OOM.
Ou du moins, faites de ce comportement une option configurable, en raison des inconvénients du problème de performances avec GC.Collect.
Maintenant, j'ai beaucoup de code comme celui-ci dans mon application pour "résoudre" le problème:
(Notez que le comportement Thread.Sleep () est un comportement vraiment spécifique à l'application, car nous exécutons un service de mise en cache ORM, et le service prend un certain temps pour libérer tous les objets mis en cache, si la RAM dépasse certaines valeurs prédéfinies. quelques secondes la première fois et a augmenté le temps d'attente à chaque occurrence de MOO.)
la source
GC.Collect
. Puisqu'il a un effet à l'échelle de l'application, seule l'application devrait le faire (le cas échéant).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 le font déjà - j'ai vu des indications selon lesquelles l'un des déclencheurs internes du GC est certains échecs d'allocation de mémoire.Vous devriez essayer d'éviter d'utiliser GC.Collect () car c'est très cher. Voici un exemple:
RÉSULTAT DU TEST: UTILISATION DU CPU 12%
Lorsque vous passez à ceci:
RÉSULTAT DU TEST: UTILISATION DU CPU 2-3%
la source
Une autre raison est lorsque vous avez un SerialPort ouvert sur un port USB COM, puis que le périphérique USB est débranché. Étant donné que SerialPort a été ouvert, la ressource contient une référence au port précédemment connecté dans le registre du système. Le registre du système sera alors des données périmées , de sorte que la liste des ports disponibles sera erronée. Par conséquent, le port doit être fermé.
L'appel de SerialPort.Close () sur le port appelle Dispose () sur l'objet, mais il reste en mémoire jusqu'à ce que le garbage collection s'exécute réellement, ce qui fait que le registre reste obsolète jusqu'à ce que le garbage collector décide de libérer la ressource.
Depuis https://stackoverflow.com/a/58810699/8685342 :
la source
Ce n'est pas si pertinent pour la question, mais pour les transformations XSLT dans .NET (XSLCompiledTranform), vous n'aurez peut-être pas le choix. Un autre candidat est le contrôle MSHTML.
la source
Si vous utilisez une version de .net inférieure à 4.5, la collecte manuelle peut être inévitable (surtout si vous avez affaire à de nombreux «gros objets»).
ce lien décrit pourquoi:
https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/
la source
une bonne raison d'appeler GC est sur les petits ordinateurs ARM avec peu de mémoire, comme le Raspberry PI (fonctionnant en mono). Si les fragments de mémoire non alloués utilisent trop de RAM système, alors le système d'exploitation Linux peut devenir instable. J'ai une application où je dois appeler GC toutes les secondes (!) Pour me débarrasser des problèmes de débordement de mémoire.
Une autre bonne solution consiste à jeter les objets lorsqu'ils ne sont plus nécessaires. Malheureusement, ce n'est pas si facile dans de nombreux cas.
la source
Puisqu'il existe un petit tas d'objets (SOH) et un tas d'objets grands (LOH)
Nous pouvons appeler GC.Collect () pour effacer l'objet de dé-référence dans SOP et déplacer l'objet vécu vers la génération suivante.
Dans .net4.5, nous pouvons également compacter LOH en utilisant largeobjectheapcompactionmode
la source
Si vous créez beaucoup de nouveaux
System.Drawing.Bitmap
objets, le garbage collector ne les efface pas. Finalement, GDI + pensera que vous manquez de mémoire et lancera une exception «Le paramètre n'est pas valide». Appeler deGC.Collect()
temps en temps (pas trop souvent!) Semble résoudre ce problème.la source