.net - Anatomie d'une "fuite de mémoire"

Translate

Dans la perspective .NET:

  • Qu'est-ce qu'unfuite de mémoire?
  • Comment pouvez-vous déterminer si votre application fuit? Quels sont les effets?
  • Comment éviter une fuite de mémoire?
  • Si votre application a une fuite de mémoire, disparaît-elle lorsque le processus se termine ou est arrêté? Ou est-ce que les fuites de mémoire dans votre application affectent d'autres processus sur le système même après l'achèvement du processus?
  • Et qu'en est-il du code non géré accessible via COM Interop et / ou P / Invoke?
This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

La meilleure explication que j'ai vue se trouve dans le chapitre 7 du gratuitLivre électronique Fondements de la programmation.

Fondamentalement, dans.NETune fuite de mémoire se produit lorsque les objets référencés sont enracinés et ne peuvent donc pas être récupérés. Cela se produit accidentellement lorsque vous conservez des références au-delà de la portée prévue.

Vous saurez que vous avez des fuites lorsque vous commencez à obtenir des OutOfMemoryExceptions ou que votre utilisation de la mémoire dépasse ce à quoi vous vous attendez (PerfMona de jolis compteurs de mémoire).

Compréhension.NETLe modèle de mémoire de est votre meilleur moyen de l'éviter. Plus précisément, comprendre comment fonctionne le garbage collector et comment fonctionnent les références - encore une fois, je vous renvoie au chapitre 7 de l'e-book. Aussi, soyez conscient des pièges courants, probablement les événements les plus courants. Si objetAest inscrit à un événement sur l'objetB, puis objecteArestera dans les parages jusqu'à ce que l'objetBdisparaît parce queBcontient une référence àA. La solution consiste à désenregistrer vos événements lorsque vous avez terminé.

Bien sûr, un bon profil de mémoire vous permettra de voir vos graphiques d'objets et d'explorer l'imbrication / le référencement de vos objets pour voir d'où viennent les références et quel objet racine est responsable (profil de fourmis porte-rouge, JetBrains dotMemory,memprofilersont de très bons choix, ou vous pouvez utiliser le texte uniquementWinDbgetSOS, mais je recommande fortement un produit commercial / visuel à moins que vous ne soyez un vrai gourou).

Je crois que le code non managé est sujet à ses fuites de mémoire typiques, sauf que les références partagées sont gérées par le garbage collector. Je peux me tromper sur ce dernier point.

La source
Translate

À proprement parler, une fuite de mémoire consomme de la mémoire qui n'est «plus utilisée» par le programme.

«Plus utilisé» a plus d'un sens, cela pourrait signifier «plus aucune référence à lui», c'est-à-dire totalement irrécupérable, ou cela pourrait signifier, référencé, récupérable, inutilisé mais le programme garde quand même les références. Seul le dernier s'applique à .Net pourobjets parfaitement gérés. Cependant, toutes les classes ne sont pas parfaites et à un moment donné, une implémentation non gérée sous-jacente pourrait perdre des ressources de manière permanente pour ce processus.

Dans tous les cas, l'application consomme plus de mémoire que strictement nécessaire. Les effets secondaires, en fonction de la quantité divulguée, pourraient aller de zéro, à un ralentissement causé par une collecte excessive, à une série d'exceptions de mémoire et enfin à une erreur fatale suivie d'une interruption forcée du processus.

Vous savez qu'une application a un problème de mémoire lorsque la surveillance montre que de plus en plus de mémoire est allouée à votre processusaprès chaque cycle de ramassage des ordures. Dans ce cas, soit vous en gardez trop en mémoire, soit une implémentation sous-jacente non gérée fuit.

Pour la plupart des fuites, les ressources sont récupérées lorsque le processus est terminé, mais certaines ressources ne sont pas toujours récupérées dans certains cas précis, les poignées de curseur GDI sont réputées pour cela. Bien entendu, si vous disposez d'un mécanisme de communication interprocessus, la mémoire allouée dans l'autre processus ne sera pas libérée tant que ce processus ne la libère pas ou ne s'arrête pas.

La source
Translate

Je pense que les questions «qu'est-ce qu'une fuite de mémoire» et «quels sont les effets» ont déjà été bien répondues, mais je voulais ajouter quelques éléments sur les autres questions ...

Comment comprendre si votre application fuit

Une manière intéressante est d'ouvrirperfmonet ajoutez des traces pour# octets dans tous les tasetCollections # Gen 2, dans chaque cas en regardant simplement votre processus. Si l'exercice d'une fonctionnalité particulière entraîne une augmentation du nombre total d'octets et que la mémoire reste allouée après la prochaine collecte de génération 2, vous pouvez dire que la fonctionnalité perd de la mémoire.

Comment empêcher

D'autres bonnes opinions ont été données. J'ajouterais simplement que peut-être lele plus souvent négligéLa cause des fuites de mémoire .NET est d'ajouter des gestionnaires d'événements aux objets sans les supprimer. Un gestionnaire d'événements attaché à un objet est une forme de référence à cet objet, donc empêchera la collecte même après que toutes les autres références ont disparu. N'oubliez jamais de détacher les gestionnaires d'événements (en utilisant le-=syntaxe en C #).

La fuite disparaît-elle lorsque le processus se termine, et qu'en est-il de l'interopérabilité COM?

Lorsque votre processus se termine, toute la mémoire mappée dans son espace d'adressage est récupérée par le système d'exploitation, y compris les objets COM servis à partir des DLL. Comparativement, les objets COM peuvent être servis à partir de processus séparés. Dans ce cas, lorsque votre processus se termine, vous pouvez toujours être responsable de la mémoire allouée dans tous les processus de serveur COM que vous avez utilisés.

La source
Translate

Je définirais les fuites de mémoire comme un objet ne libérant pas toute la mémoire allouée après son achèvement. J'ai trouvé que cela peut arriver dans votre application si vous utilisez Windows API et COM (c'est-à-dire du code non géré qui contient un bogue ou n'est pas géré correctement), dans le cadre et dans des composants tiers. J'ai également constaté que le fait de ne pas se réveiller après avoir utilisé certains objets comme des stylos pouvait causer le problème.

J'ai personnellement souffert d'exceptions de mémoire insuffisante qui peuvent être causées mais ne sont pas exclusives à des fuites de mémoire dans les applications dot net. (Le MOO peut également provenir de l'épinglage voirÉpingler Artical). Si vous n'obtenez pas d'erreurs MOO ou si vous devez confirmer si c'est une fuite de mémoire qui en est à l'origine, le seul moyen est de profiler votre application.

J'essaierais également d'assurer ce qui suit:

a) Tout ce qui implémente Idisposable est éliminé soit en utilisant un bloc finally ou l'instruction using, cela inclut les pinceaux, les stylos, etc. (certaines personnes soutiennent de tout remettre à rien en plus)

b) Tout ce qui a une méthode close est à nouveau fermé en utilisant finally ou l'instruction using (bien que j'ai trouvé que using ne se ferme pas toujours selon si vous avez déclaré l'objet en dehors de l'instruction using)

c) Si vous utilisez du code non géré / des API Windows, celles-ci sont traitées correctement après. (certains ont des méthodes de nettoyage pour libérer des ressources)

J'espère que cela t'aides.

La source
Translate

Si vous devez diagnostiquer une fuite de mémoire dans .NET, vérifiez ces liens:

http://msdn.microsoft.com/en-us/magazine/cc163833.aspx

http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

Ces articles décrivent comment créer un vidage mémoire de votre processus et comment l'analyser afin que vous puissiez d'abord déterminer si votre fuite n'est pas gérée ou gérée, et si elle est gérée, comment déterminer d'où elle provient.

Microsoft dispose également d'un outil plus récent pour aider à générer des vidages sur incident, pour remplacer ADPlus, appelé DebugDiag.

http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en

La source
Translate

Utilisation de CLR Profiler de Microsofthttp://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=enest un excellent moyen de déterminer quels objets contiennent de la mémoire, quel flux d'exécution conduit à la création de ces objets, et également de surveiller quels objets vivent où sur le tas (fragmentation, LOH, etc.).

La source
Translate

La meilleure explication du fonctionnement du garbage collector est dans Jeff RichtersCLR via C #livre, (Ch.20). La lecture de ceci donne une bonne base pour comprendre comment les objets persistent.

L'une des causes les plus courantes d'enracinement accidentel d'objets est le raccordement d'événements hors d'une classe. Si vous connectez un événement externe

par exemple

SomeExternalClass.Changed += new EventHandler(HandleIt);

et oubliez de le décrocher lorsque vous supprimez, alors SomeExternalClass a une référence à votre classe.

Comme mentionné ci-dessus, leProfileur de mémoire SciTechest excellent pour vous montrer les racines des objets que vous soupçonnez de fuir.

Mais il existe également un moyen très rapide de vérifier un type particulier est simplement d'utiliser WnDBG (vous pouvez même l'utiliser dans la fenêtre immédiate de VS.NET en étant attaché):

.loadby sos mscorwks
!dumpheap -stat -type <TypeName>

Maintenant, faites quelque chose qui, selon vous, éliminera les objets de ce type (par exemple, fermez une fenêtre). Il est pratique ici d'avoir un bouton de débogage quelque part qui fonctionneraSystem.GC.Collect()deux-trois fois.

Puis cours!dumpheap -stat -type <TypeName>encore. Si le nombre n'a pas baissé ou n'a pas baissé autant que prévu, vous avez une base pour une enquête plus approfondie. (J'ai eu cette astuce d'un séminaire donné parIngo Rammer).

La source
Translate

Je suppose que dans un environnement géré, une fuite serait que vous gardiez une référence inutile à une grande partie de la mémoire.

La source
Translate

Pourquoi les gens pensent-ils qu'une fuite de mémoire dans .NET n'est pas la même chose qu'une autre fuite?

Une fuite de mémoire se produit lorsque vous vous attachez à une ressource et ne la laissez pas partir. Vous pouvez le faire à la fois en codage géré et non géré.

En ce qui concerne .NET et d'autres outils de programmation, il y a eu des idées sur la récupération de place et d'autres moyens de minimiser les situations qui feront fuir votre application. Mais la meilleure méthode pour éviter les fuites de mémoire est que vous devez comprendre votre modèle de mémoire sous-jacent et son fonctionnement sur la plate-forme que vous utilisez.

Croire que GC et d'autres magies nettoieront votre gâchis est le chemin le plus court vers les fuites de mémoire, et sera difficile à trouver plus tard.

Lors du codage non géré, vous vous assurez normalement de nettoyer, vous savez que les ressources que vous prenez en main seront de votre responsabilité de nettoyer, pas celles du concierge.

Dans .NET par contre, beaucoup de gens pensent que le GC va tout nettoyer. Eh bien, il en fait pour vous, mais vous devez vous assurer qu'il en est ainsi. .NET englobe beaucoup de choses, vous ne savez donc pas toujours si vous avez affaire à une ressource gérée ou non, et vous devez vous assurer de ce à quoi vous avez affaire. La gestion des polices, des ressources GDI, de l'annuaire actif, des bases de données, etc. est généralement des choses que vous devez rechercher.

En termes gérés, je mettrai mon cou sur la ligne pour dire qu'il disparaît une fois que le processus est tué / supprimé.

Je vois que beaucoup de gens ont cela, et j'espère vraiment que cela prendra fin. Vous ne pouvez pas demander à l'utilisateur de mettre fin à votre application pour nettoyer votre désordre! Jetez un œil à un navigateur, qui peut être IE, FF, etc., puis ouvrez, disons, Google Reader, laissez-le rester pendant quelques jours et regardez ce qui se passe.

Si vous ouvrez ensuite un autre onglet dans le navigateur, surfez sur un site, puis fermez l'onglet qui hébergeait l'autre page qui a fait la fuite du navigateur, pensez-vous que le navigateur libérera la mémoire? Ce n'est pas le cas avec IE. Sur mon ordinateur, IE consommera facilement 1 Gio de mémoire en peu de temps (environ 3-4 jours) si j'utilise Google Reader. Certaines pages d'actualités sont encore pires.

La source
Translate

Je suppose que dans un environnement géré, une fuite serait que vous gardiez une référence inutile à une grande partie de la mémoire.

Absolument. En outre, ne pas utiliser la méthode .Dispose () sur des objets jetables lorsque cela est approprié peut provoquer des fuites de mémoire. Le moyen le plus simple de le faire est d'utiliser un bloc using car il exécute automatiquement .Dispose () à la fin:

StreamReader sr;
using(sr = new StreamReader("somefile.txt"))
{
    //do some stuff
}

Et si vous créez une classe qui utilise des objets non gérés, si vous n'implémentez pas correctement IDisposable, vous pourriez provoquer des fuites de mémoire pour les utilisateurs de votre classe.

La source
Translate

Toutes les fuites de mémoire sont résolues par l'arrêt du programme.

Fuite de mémoire suffisante et le système d'exploitation peut décider de résoudre le problème en votre nom.

La source
Pat
Translate

Je serai d'accord avec Bernard pour dire dans .net ce que serait une fuite de mémoire.

Vous pouvez profiler votre application pour voir son utilisation de la mémoire et déterminer que si elle gère beaucoup de mémoire alors qu'elle ne devrait pas l'être, vous pourriez dire qu'elle a une fuite.

En termes gérés, je mettrai mon cou sur la ligne pour dire qu'il disparaît une fois que le processus est tué / supprimé.

Le code non managé est sa propre bête et s'il y a une fuite, il suivra un mem standard. définition des fuites.

La source
Translate

Gardez également à l'esprit que .NET a deux tas, l'un étant le tas d'objets volumineux. Je crois que des objets d'environ 85k ou plus sont placés sur ce tas. Ce tas a des règles de durée de vie différentes de celles du tas normal.

Si vous créez de grandes structures de mémoire (dictionnaire ou liste), il serait prudent d'aller chercher quelles sont les règles exactes.

En ce qui concerne la récupération de la mémoire à la fin du processus, sauf si vous exécutez Win98 ou ses équivalents, tout est remis au système d'exploitation à la fin. Les seules exceptions sont les éléments ouverts entre processus et un autre processus a toujours la ressource ouverte.

Les objets COM peuvent être difficiles à gérer. Si vous utilisez toujours leIDisposemotif, vous serez en sécurité. Mais j'ai rencontré quelques assemblys d'interopérabilité qui implémententIDispose. La clé ici est d'appelerMarshal.ReleaseCOMObjectquand vous en avez terminé. Les objets COM utilisent toujours le comptage de référence COM standard.

La source
Translate

j'ai trouvé.Net Memory Profilerune très bonne aide pour trouver des fuites de mémoire dans .Net. Ce n'est pas gratuit comme le Microsoft CLR Profiler, mais c'est plus rapide et plus pertinent à mon avis. UNE

La source
Translate

Une définition est:Impossible de libérer de la mémoire inaccessible, qui ne peut plus être allouée au nouveau processus pendant l'exécution du processus d'allocation. Il peut principalement être guéri en utilisant des techniques GC ou détecté par des outils automatisés.

Pour plus d'informations, s'il vous plaît visitezhttp://all-about-java-and-weblogic-server.blogspot.in/2014/01/what-is-memory-leak-in-java.html.

La source