Bien que je comprenne les sérieuses implications de jouer avec cette fonction (ou du moins c'est ce que je pense), je ne vois pas pourquoi cela devient l'une de ces choses que les programmeurs respectables n'utiliseraient jamais, même ceux qui ne le savent même pas. ce que ce est pour.
Disons que je développe une application où l'utilisation de la mémoire varie énormément en fonction de ce que fait l'utilisateur. Le cycle de vie de l'application peut être divisé en deux étapes principales: l'édition et le traitement en temps réel. Pendant la phase d'édition, supposons que des milliards, voire des billions d'objets soient créés; certains d'entre eux sont petits et d'autres pas, certains peuvent avoir des finaliseurs et d'autres pas, et supposent que leur durée de vie varie de quelques millisecondes à de longues heures. Ensuite, l'utilisateur décide de passer à l'étape en temps réel. À ce stade, supposons que la performance joue un rôle fondamental et que la moindre altération du déroulement du programme pourrait avoir des conséquences catastrophiques. La création d'objets est alors réduite au minimum possible en utilisant des pools d'objets et autres, mais ensuite, le GC intervient de manière inattendue et jette tout cela, et quelqu'un meurt.
La question: dans ce cas, ne serait-il pas judicieux d'appeler GC.Collect () avant d'entrer dans la deuxième étape?
Après tout, ces deux étapes ne se chevauchent jamais dans le temps et toutes les optimisations et statistiques que le GC aurait pu rassembler seraient ici de peu d'utilité ...
Remarque: comme certains d'entre vous l'ont souligné, .NET n'est peut-être pas la meilleure plate-forme pour une application comme celle-ci, mais cela dépasse le cadre de cette question. L'intention est de clarifier si un appel GC.Collect () peut améliorer le comportement / les performances globales d'une application ou non. Nous convenons tous que les circonstances dans lesquelles vous feriez une telle chose sont extrêmement rares, mais là encore, le GC essaie de deviner et le fait parfaitement bien la plupart du temps, mais il s'agit toujours de deviner.
Merci.
Réponses:
Du blog de Rico ...
Il semble donc que cette situation relève de la règle n ° 2, vous savez qu'il y a un moment dans le temps où de nombreux objets anciens sont morts, et ce n'est pas récurrent. Cependant, n'oubliez pas les mots d'adieu de Rico.
Mesurer, mesurer, mesurer.
la source
Si vous appelez GC.Collect () dans le code de production, vous déclarez essentiellement que vous en savez plus que les auteurs du GC. Cela peut être le cas. Cependant, ce n'est généralement pas le cas, et donc fortement déconseillé.
la source
malloc
n'a qu'une interface très simple, et ses implémentations peuvent varier suffisamment pour avoir de l'importance. Tout dépend du type de problème que vous essayez de résoudre. Simalloc
c'était "assez bon", vous n'auriez pas besoin de pool de tampons, n'est-ce pas? Le développement C / C ++ regorge d'exemples où vous essayez de deviner le système d'exploitation / le moteur d'exécution / les bibliothèques parce que vous en savez mieux (et parfois, vous le faites vraiment). De nombreuses applications critiques pour les performances évitent totalement d'utiliser des allocateurs système / d'exécution. Jeux utilisés pour pré-allouer toute la mémoire au démarrage (tableaux de taille constante, etc.).Alors, qu'en est-il lorsque vous utilisez des objets COM comme MS Word ou MS Excel à partir de .NET? Sans appeler
GC.Collect
après avoir libéré les objets COM, nous avons constaté que les instances d'application Word ou Excel existent toujours.En fait, le code que nous utilisons est:
Alors, serait-ce une mauvaise utilisation du ramasse-miettes? Si oui, comment faire mourir les objets Interop? Aussi , si ce n'est pas destiné à être utilisé comme cela, pourquoi est
GC
de »Collect
méthode mêmePublic
?la source
Eh bien, le GC est l'une de ces choses avec lesquelles j'ai une relation d'amour / haine. Nous l'avons brisé dans le passé via VistaDB et avons blogué à ce sujet. Ils l'ont corrigé, mais il leur faut beaucoup de temps pour obtenir des correctifs sur des choses comme celle-ci.
Le GC est complexe, et une approche universelle est très, très difficile à réaliser sur quelque chose d'aussi vaste. MS a fait un assez bon travail, mais il est parfois possible de tromper le GC.
En général, vous ne devriez pas ajouter un à
Collect
moins que vous ne sachiez que vous venez de vider une tonne de mémoire et cela ira à une crise de mi-vie si le GC ne le nettoie pas maintenant.Vous pouvez bousiller toute la machine avec une série de mauvaises
GC.Collect
déclarations. La nécessité d'une instruction de collecte indique presque toujours une erreur sous-jacente plus importante. La fuite de mémoire est généralement liée à des références et à un manque de compréhension de leur fonctionnement. Ou en utilisant leIDisposable
objets qui n'en ont pas besoin et en mettant une charge beaucoup plus élevée sur le GC.Surveillez attentivement le pourcentage de temps passé en GC grâce aux compteurs de performance du système. Si vous voyez votre application utiliser 20% ou plus de son temps dans le GC, vous avez de sérieux problèmes de gestion des objets (ou un modèle d'utilisation anormal). Vous voulez toujours minimiser le temps passé par le GC, car cela accélérera l'ensemble de votre application.
Il est également important de noter que le GC est différent sur les serveurs des postes de travail. J'ai vu un certain nombre de petits problèmes difficiles à dépister avec des gens qui ne les testent pas tous les deux (ou même pas conscients qu'ils sont deux).
Et pour être aussi complet que possible dans ma réponse, vous devez également tester sous Mono si vous ciblez également cette plate-forme. Puisqu'il s'agit d'une implémentation totalement différente, elle peut rencontrer des problèmes totalement différents de l'implémentation MS.
la source
Il y a des situations où c'est utile, mais en général, cela devrait être évité. Vous pouvez le comparer à GOTO, ou à conduire un cyclomoteur: vous le faites quand vous en avez besoin, mais vous n'en parlez pas à vos amis.
la source
D'après mon expérience, il n'a jamais été conseillé de faire un appel à GC.Collect () en code de production. En débogage, oui, il a ses avantages pour aider à clarifier les fuites de mémoire potentielles. Je suppose que ma raison fondamentale est que le GC a été écrit et optimisé par des programmeurs beaucoup plus intelligents que moi, et si j'arrive à un point où je sens que je dois appeler GC.Collect (), c'est un indice que je me suis éloigné du chemin quelque part. Dans votre situation, il ne semble pas que vous ayez réellement des problèmes de mémoire, mais simplement que vous vous inquiétez de l'instabilité que la collection apportera à votre processus. Voyant qu'il ne nettoiera pas les objets encore utilisés, et qu'il s'adapte très rapidement à la fois à la hausse et à la baisse des demandes, je pense que vous n'aurez pas à vous en soucier.
la source
L'une des principales raisons d'appeler GC.Collect () est lorsque vous venez d'effectuer un événement significatif qui crée beaucoup de déchets, comme ce que vous décrivez. Appeler GC.Collect () peut être une bonne idée ici; sinon, le GC pourrait ne pas comprendre qu'il s'agissait d'un événement «ponctuel».
Bien sûr, vous devez le profiler et voir par vous-même.
la source
Eh bien, évidemment, vous ne devriez pas écrire du code avec des exigences en temps réel dans des langages avec un garbage collection non en temps réel.
Dans un cas avec des étapes bien définies, il n'y a aucun problème avec le déclenchement du ramasse-miettes. Mais ce cas est extrêmement rare. Le problème est que de nombreux développeurs vont essayer de l'utiliser pour résoudre les problèmes dans un style culte du fret, et l'ajouter sans discernement causera des problèmes de performances.
la source
L'appel de GC.Collect () force le CLR à faire un parcours de pile pour voir si chaque objet peut vraiment être libéré en vérifiant les références. Cela affectera l'évolutivité si le nombre d'objets est élevé et est également connu pour déclencher le garbage collection trop souvent. Faites confiance au CLR et laissez le garbage collector s'exécuter le cas échéant.
la source
En fait, je ne pense pas que ce soit une très mauvaise pratique d'appeler GC.Collect.
Il peut y avoir des cas où nous en avons besoin. Juste par exemple, j'ai un formulaire qui exécute un thread, qui à son tour ouvre différentes tables dans une base de données, extrait le contenu d'un champ BLOB dans un fichier temporaire, crypte le fichier, puis lit le fichier dans un binarystream et de nouveau dans un BLOB champ dans une autre table.
L'ensemble de l'opération prend beaucoup de mémoire, et il n'est pas certain du nombre de lignes et de la taille du contenu du fichier dans les tables.
J'avais l'habitude d'obtenir souvent OutofMemory Exception et j'ai pensé qu'il serait sage d'exécuter périodiquement GC.Collect en fonction d'une variable de compteur. J'incrémente un compteur et lorsqu'un niveau spécifié est atteint, GC est appelé pour collecter les déchets qui se sont formés et pour récupérer toute mémoire perdue en raison de fuites de mémoire imprévues.
Après cela, je pense que cela fonctionne bien, du moins pas d'exception !!!
J'appelle de la manière suivante:
la source
Sous .net, le temps requis pour effectuer un garbage collection est beaucoup plus fortement lié à la quantité de choses qui ne sont pas des déchets, qu'à la quantité de choses qui l'est. En effet, à moins qu'un objet ne remplace
Finalize
(soit explicitement, soit via un destructeur C #), est la cible de aWeakReference
, se trouve sur le tas d'objets volumineux, ou est spécial d'une autre manière liée à gc, la seule chose identifiant la mémoire dans laquelle il se trouve comme étant un objet est l'existence de références enracinées à celui-ci. Sinon, le fonctionnement du GC équivaut à prendre d'un bâtiment tout ce qui a de la valeur, à dynamiter le bâtiment, à en construire un nouveau sur le site de l'ancien et à y mettre tous les objets de valeur. L'effort requis pour dynamiter le bâtiment est totalement indépendant de la quantité de déchets qu'il contient.Par conséquent, l'appel
GC.Collect
est susceptible d'augmenter la quantité globale de travail que le système doit effectuer. Cela retardera l'occurrence de la prochaine collection, mais fera probablement autant de travail immédiatement que la prochaine collection l'aurait exigé lorsqu'elle s'est produite; au moment où la prochaine collecte aurait eu lieu, le temps total passé à collecter aura été à peu près le même que celui qui n'avaitGC.Collect
pas été appelé, mais le système aura accumulé des déchets, ce qui obligera la collecte suivante à être requise plus tôt queGC.Collect
jamais été appelé.Les moments que je vois
GC.Collect
vraiment utiles sont ceux où l'on a besoin de mesurer l'utilisation de la mémoire de certains codes (puisque les chiffres d'utilisation de la mémoire ne sont vraiment significatifs qu'après une collection), ou de profiler lequel de plusieurs algorithmes est le meilleur (en appelant GC.Collect () avant d'exécuter chacun de plusieurs morceaux de code peut aider à garantir un état de base cohérent). Il y a quelques autres cas où l'on pourrait savoir des choses que le GC ne sait pas, mais à moins que l'on n'écrive un programme à un seul thread, il n'y a aucun moyen de savoir qu'unGC.Collect
appel qui aiderait les structures de données d'un thread à éviter "la crise de la mi-vie "ne ferait pas en sorte que les données d'autres threads aient une" crise de la quarantaine "qui aurait autrement été évitée.la source
Création d'images en boucle - même si vous appelez disposer, la mémoire n'est pas récupérée. Collecte des ordures à chaque fois. Je suis passé de 1,7 Go de mémoire sur mon application de traitement photo à 24 Mo et les performances sont excellentes.
Il est absolument temps d'appeler GC.Collect.
la source
Dispose
n'est pas censé libérer de la mémoire gérée. Vous ne semblez pas savoir comment fonctionne le modèle de mémoire dans .NET.Nous avons eu un problème similaire avec le garbage collector ne collectant pas les déchets et ne libérant pas de mémoire.
Dans notre programme, nous traitions des feuilles de calcul Excel de taille modeste avec OpenXML. Les feuilles de calcul contenaient de 5 à 10 «feuilles» avec environ 1 000 lignes de 14 colonnes.
Le programme dans un environnement 32 bits (x86) plantait avec une erreur "mémoire insuffisante". Nous l'avons fait fonctionner dans un environnement x64, mais nous voulions une meilleure solution.
Nous en avons trouvé un.
Voici quelques fragments de code simplifiés de ce qui n'a pas fonctionné et de ce qui a fonctionné lorsqu'il s'agit d'appeler explicitement le garbage collector pour libérer de la mémoire des objets supprimés.
L'appel du GC depuis l'intérieur du sous-programme n'a pas fonctionné. La mémoire n'a jamais été récupérée ...
En déplaçant l'appel GC hors de la portée du sous-programme, la mémoire a été collectée et la mémoire a été libérée.
J'espère que cela aide les autres qui sont frustrés par le garbage collection .NET quand il semble ignorer les appels à
GC.Collect()
.Paul Smith
la source
Il n'y a rien de mal à appeler explicitement une collection. Certaines personnes veulent vraiment croire que s'il s'agit d'un service fourni par le fournisseur, ne le remettez pas en question. Oh, et tous ces gels aléatoires aux mauvais moments de votre application interactive? La prochaine version le rendra meilleur!
Laisser un processus d'arrière-plan gérer la manipulation de la mémoire signifie ne pas avoir à le gérer nous-mêmes, c'est vrai. Mais cela ne signifie pas logiquement qu'il est préférable pour nous de ne pas y faire face nous-mêmes en toutes circonstances. Le GC est optimisé pour la plupart des cas. Mais cela ne signifie pas logiquement qu'il est optimisé dans tous les cas.
Avez-vous déjà répondu à une question ouverte telle que «quel est le meilleur algorithme de tri» avec une réponse définitive? Si tel est le cas, ne touchez pas le GC. Pour ceux d'entre vous qui ont demandé les conditions ou qui ont donné des réponses de type «dans ce cas», vous pouvez vous renseigner sur le GC et savoir quand l'activer.
Je dois dire que j'ai eu des gels d'applications dans Chrome et Firefox qui me frustrent, et même dans certains cas, la mémoire se développe sans entrave - si seulement ils apprenaient à appeler le ramasse-miettes - ou me donnaient un afin que, lorsque je commence à lire le texte d'une page, je puisse la frapper et ainsi être libre de gel pendant les 20 prochaines minutes.
la source
Je pense que vous avez raison sur le scénario, mais je ne suis pas sûr de l'API.
Microsoft dit que dans de tels cas, vous devez ajouter une pression de mémoire pour indiquer au GC qu'il devrait bientôt effectuer une collecte.
la source
Qu'est ce qui ne va pas avec ça? Le fait que vous doutiez du ramasse-miettes et de l'allocateur de mémoire, qui à eux deux ont une bien meilleure idée de l'utilisation réelle de la mémoire de votre application au moment de l'exécution que vous.
la source
Le désir d'appeler GC.Collect () essaie généralement de dissimuler les erreurs que vous avez faites ailleurs!
Ce serait mieux si vous trouviez où vous avez oublié de disposer des choses dont vous n'avez plus besoin.
la source
En bout de ligne, vous pouvez profiler l'application et voir comment ces collections supplémentaires affectent les choses. Je suggérerais de rester à l'écart, sauf si vous allez profiler. Le GC est conçu pour prendre soin de lui-même et à mesure que le temps d'exécution évolue, il peut augmenter son efficacité. Vous ne voulez pas qu'un tas de code traîne qui puisse gâcher les travaux et ne pas pouvoir profiter de ces améliorations. Il existe un argument similaire en faveur de l'utilisation de foreach au lieu de for, à savoir que de futures améliorations sous les couvertures peuvent être ajoutées à foreach et que votre code n'a pas à changer pour en profiter.
la source
Le .NET Framework lui-même n'a jamais été conçu pour s'exécuter dans un environnement en temps réel. Si vous avez vraiment besoin d'un traitement en temps réel, vous utiliserez soit un langage temps réel intégré qui n'est pas basé sur .NET, soit le .NET Compact Framework s'exécutant sur un appareil Windows CE.
la source
Le pire que cela puisse faire est de bloquer un peu votre programme. Donc, si cela vous convient, faites-le. Habituellement, il n'est pas nécessaire pour les clients lourds ou les applications Web avec principalement une interaction utilisateur.
J'ai constaté que parfois les programmes avec des threads de longue durée, ou des programmes par lots, obtiennent une exception OutOfMemory même s'ils éliminent correctement les objets. Je me souviens d'un traitement de transaction de base de données métier; l'autre était une routine d'indexation sur un thread d'arrière-plan dans une application client lourd.
Dans les deux cas, le résultat était simple: pas de GC.Collect, manque de mémoire, de manière cohérente; GC.Collect, des performances sans faille.
Je l'ai essayé plusieurs fois pour résoudre des problèmes de mémoire, en vain. Je l'ai sorti.
En bref, ne le mettez pas à moins que vous n'obteniez des erreurs. Si vous l'avez inséré et que cela ne résout pas le problème de mémoire, retirez-le. N'oubliez pas de tester en mode Release et de comparer des pommes avec des pommes.
La seule fois où les choses peuvent mal tourner, c'est lorsque vous devenez moraliste à ce sujet. Ce n'est pas une question de valeurs; de nombreux programmeurs sont morts et sont allés droit au paradis avec de nombreux GC.Collects inutiles dans leur code, qui leur survit.
la source