Anatomie d'une « fuite de mémoire »

voix
159

Dans la perspective .NET:

  • Qu'est - ce qu'un fuite de mémoire ?
  • Comment pouvez-vous déterminer si vos fuites d'application? Quels sont les effets?
  • Comment pouvez-vous empêcher une fuite de mémoire?
  • Si votre application a fuite de mémoire, il ne disparaîtra lorsque le processus sort ou est tué? Ou bien 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-code non managé accessible via COM Interop et / ou P / Invoke?
Créé 01/08/2008 à 16:12
source utilisateur
Dans d'autres langues...                            


15 réponses

voix
106

La meilleure explication que je l' ai vu est au chapitre 7 de la liberté Fondements de la programmation e-book .

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

Vous saurez que vous avez des fuites lorsque vous commencez à obtenir OutOfMemoryExceptions ou votre utilisation de la mémoire GOES au - delà de ce que vous attendez ( PerfMon a de bons compteurs de mémoire).

Comprendre .NET modèle de mémoire de est votre meilleur moyen de l' éviter. Plus précisément, comprendre comment le garbage collector fonctionne et comment les références fonctionnent - encore une fois, je vous renvoie au chapitre 7 du livre électronique. Aussi, soyez conscient des pièges courants, probablement des événements étant les plus courantes. Si l' objet A est inscrit à un événement sur l' objet B , alors l' objet A collera autour jusqu'à ce que l' objet B disparaît parce que B contient une référence à A . La solution est de désenregistrer vos événements lorsque vous avez terminé.

Bien sûr, un bon profil de mémoire vous permettra de voir vos graphes d'objets et d' explorer l'imbrication / référencement de vos objets pour voir où les références viennent et quel objet racine est responsable ( fourmis rouges porte profil , JetBrains dotMemory, memprofiler sont vraiment bons choix, ou vous pouvez utiliser le texte uniquement WinDbg et SOS , mais je vous recommande fortement un produit commercial / visuel , sauf si vous êtes un vrai gourou).

Je crois que le code non managé est soumis à 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.

Créé 01/08/2008 à 16:28
source utilisateur

voix
32

Au sens strict, une fuite de mémoire consomme la mémoire qui est « ne sont plus utilisés » par le programme.

« Plus utilisé » a plus d'un sens, cela pourrait signifier « non plus référence à elle », qui est, totalement irrécupérable, ou cela pourrait signifier, référencé, récupérable, utilisé , mais le programme conserve les références de toute façon. Seul le plus tard applique à .NET pour objets gérés parfaitement . Cependant, toutes les classes sont parfaits et à un moment donné une mise en œuvre non gérée sous - jacente pourrait fuir de façon permanente les ressources pour ce processus.

Dans tous les cas, l'application consomme plus de mémoire que strictement nécessaire. Les effets de côtés, selon la ammount fuite, pourraient aller de zéro, au ralentissement causé par la collecte excessive, à une série d'exceptions de mémoire et, enfin, une erreur fatale suivie par la fin du processus forcé.

Vous savez qu'une application a un problème de mémoire lorsque la surveillance montre que de plus en plus la mémoire est allouée à votre processus après chaque cycle de collecte des ordures . Dans ce cas, vous pouvez conserver trop en mémoire, ou une mise en œuvre non gérée sous - jacente 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és dans certains cas précis, les poignées de curseur GDI sont connus pour cela. Bien sûr, si vous avez un mécanisme de communication interprocessus, la mémoire allouée dans l'autre processus ne serait pas libéré jusqu'à ce processus libère ou se termine.

Créé 01/08/2008 à 18:52
source utilisateur

voix
28

Je pense que la « ce qui est une fuite de mémoire » et « quels sont les effets » des questions ont été bien répondu déjà, mais je voulais ajouter quelques choses sur les autres questions ...

Comment comprendre si vos fuites d'application

Une façon intéressante est d'ouvrir perfmon et ajouter des traces pour # octets dans tous les tas et # Gen 2 collections , dans chaque cas , simplement regarder votre processus. Si l' exercice d' une fonction particulière provoque le total des octets à augmenter, et que la mémoire reste allouée après la prochaine collection Gen 2, vous pourriez dire que la fonction des fuites de mémoire.

Comment empêcher

D' autres bonnes opinions ont été données. Je voudrais juste ajouter que peut - être le plus souvent négligé cause de fuites de mémoire .NET est d'ajouter des gestionnaires d'événements à des objets sans les enlever. Un gestionnaire d'événement attaché à un objet est une forme de référence à cet objet, donc empêchera la collecte même après toutes les autres références ont disparu. Rappelez - vous toujours de détacher des gestionnaires d'événements ( en utilisant la -=syntaxe C #).

Est-ce que la fuite disparaissent lorsque le processus se termine, et qu'en est-COM Interop?

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

Créé 15/08/2008 à 17:11
source utilisateur

voix
18

Si vous avez besoin pour diagnostiquer une fuite de mémoire dans .NET, consultez 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 une image mémoire de votre processus et comment l'analyser afin que vous pouvez d'abord déterminer si votre fuite est géré ou non géré, et si elle est gérée, comment savoir où il vient.

Microsoft a également un outil plus récent pour aider à générer des décharges d'accident, pour remplacer ADPlus, appelé DebugDiag.

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

Créé 15/08/2008 à 00:16
source utilisateur

voix
18

Je définirais les fuites de mémoire comme un objet non de libérer toute la mémoire allouée après qu'il a terminé. J'ai trouvé cela peut se produire dans votre application si vous utilisez Windows API et COM (code non géré qui a un bogue ou n'est pas géré correctement), dans le cadre et dans les composants tiers. Je l'ai aussi trouvé pas dépannant après l'utilisation de certains objets comme les stylos peuvent provoquer le problème.

J'ai personnellement souffert Sur les exceptions de mémoire qui peuvent être causés , mais ne sont pas exclusifs à des fuites de mémoire dans les applications dot net. (OOM peut également provenir de épinglant voir épinglage Artical ). Si vous ne recevez pas les erreurs de OOM ou besoin de confirmer si elle est une fuite de mémoire à l' origine il alors la seule façon est de profiler votre application.

Je voudrais aussi essayer et vérifier les points suivants:

a) Tout ce qui implémente IDisposable est disposé soit à l'aide d'un bloc finally ou la déclaration en utilisant ces comprennent des brosses, des stylos, etc. (certaines personnes soutiennent à mettre tout à rien en plus)

b) Tout ce qui a une méthode proche est fermée à l'aide à nouveau ou enfin l'instruction à l'aide (bien que je l'ai trouvé à l'aide ne sont pas toujours à proximité en fonction si vous déclarez l'objet en dehors de la déclaration à l'aide)

c) Si vous utilisez le code non managé / Windows API est que ceux-ci sont traitées correctement après. (Certains ont nettoyer les méthodes de libérer des ressources)

J'espère que cela t'aides.

Créé 01/08/2008 à 18:57
source utilisateur

voix
15

En utilisant CLR Profiler de Microsoft http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en est une excellente façon de déterminer quels objets tiennent la mémoire, ce qui conduit de flux d'exécution à la création de ces objets, et le suivi également les objets en direct où sur le tas (fragmentation, LOH, etc.).

Créé 16/08/2008 à 20:54
source utilisateur

voix
14

La meilleure explication de la façon dont le garbage collector fonctionne est Jeff Richters CLR via C # livre (Ch. 20). La lecture de ce fait une grande mise à la terre pour comprendre comment les objets persistent.

L'une des causes des objets enracinant est accidentellement les plus courants en raccordant les événements outisde une classe. Si vous raccordez un événement extérieur

par exemple

SomeExternalClass.Changed += new EventHandler(HandleIt);

et oublier de décrochez à quand vous disposer, puis SomeExternalClass a une ref à votre classe.

Comme mentionné ci - dessus, le profileur de mémoire SciTech est excellent à vous montrer les racines d'objets que vous soupçonnez fuient.

Mais il y a aussi un moyen très rapide pour vérifier un type particulier est simplement utiliser WnDBG (vous pouvez même l'utiliser dans la fenêtre VS.NET immédiate en annexe):

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

Maintenant , faites quelque chose que vous pensez disposer les objets de ce type (par exemple , fermer une fenêtre). Il est ici utile d'avoir un endroit bouton de débogage qui se déroulera System.GC.Collect()deux fois.

Ensuite , exécutez à !dumpheap -stat -type <TypeName>nouveau. Si le nombre n'a pas diminué, ou n'a pas diminué autant que vous attendez, alors vous avez une base pour une enquête plus approfondie. (Je suis arrivé ce conseil d'un séminaire donné par Ingo Rammer ).

Créé 27/08/2008 à 15:12
source utilisateur

voix
14

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

Créé 01/08/2008 à 16:19
source utilisateur

voix
10

Pourquoi les gens pensent qu'une fuite de mémoire dans .NET n'est pas le même que toute autre fuite?

Une fuite de mémoire est lorsque vous connectez à une ressource et ne le laissez pas aller. Vous pouvez le faire aussi bien en gestion et dans le codage non géré.

En ce qui concerne .NET, et d'autres outils de programmation, il y a eu des idées sur la collecte des ordures, et d'autres façons de réduire au minimum les situations qui feront de votre fuite d'application. Mais la meilleure méthode de prévention des fuites de mémoire est que vous devez comprendre votre modèle de mémoire sous-jacente, et comment fonctionne les choses, sur la plate-forme que vous utilisez.

Estimant que GC et d'autres magie nettoyer votre désordre est le chemin court de fuites de mémoire, et il sera difficile de trouver plus tard.

Lors du codage non géré, vous faites normalement vous nettoyer, vous savez que les ressources dont vous Saisis le, sera votre responsabilité de nettoyer, pas de concierge.

Dans .NET d'autre part, beaucoup de gens pensent que le GC va nettoyer tout. Eh bien, il fait un peu pour vous, mais vous devez vous assurer qu'il en est ainsi. .NET ne wrap beaucoup de choses, de sorte que vous ne savez pas toujours si vous avez affaire à une ressource gérée ou non gérée, et vous devez vous assurer que ce que vous avez affaire. polices de manutention, GDI, Active Directory, les bases de données, etc est généralement choses que vous devez rechercher.

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

Je vois beaucoup de gens ont ce bien, 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 oeil à 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, surfer sur certains sites, puis fermez l'onglet qui a accueilli l'autre page qui a fait la fuite du navigateur, pensez-vous que le navigateur va libérer la mémoire? Pas aussi avec IE. Sur mon ordinateur IE facilement manger 1 Gio de mémoire dans un court laps de temps (environ 3-4 jours) si j'utiliser Google Reader. Certains newspages sont encore pires.

Créé 01/09/2008 à 13:19
source utilisateur

voix
10

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

Absolument. En outre, ne pas utiliser la méthode .Dispose () sur les objets à usage unique lorsque approprié peut provoquer des fuites de mémoire. La meilleure façon de le faire est avec un bloc à l'aide parce qu'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'êtes pas mise en œuvre IDisposable correctement, vous pourriez être à l'origine des fuites de mémoire pour les utilisateurs de votre classe.

Créé 05/08/2008 à 23:47
source utilisateur

voix
9

Toutes les fuites de mémoire sont résolus par la fin du programme.

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

Créé 04/08/2008 à 15:09
source utilisateur

voix
9

Je d'accord avec Bernard pour en .net ce une fuite de mem serait.

Vous pouvez profiler votre application pour voir son utilisation de la mémoire, et de déterminer que si sa la gestion d'une grande quantité de mémoire quand il ne devrait pas être vous pourriez dire qu'il a une fuite.

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

code non managé est sa propre bête et si une fuite existe à l'intérieur, il suivra une norme mem. définition des fuites.

Créé 01/08/2008 à 16:23
source utilisateur

voix
7

Gardez à l'esprit que .NET a deux tas, l'un étant le grand tas d'objets. Je crois que des objets d'environ 85k ou plus sont mis sur ce tas. Ce tas a une vie de règles différentes que le tas régulier.

Si vous créez de grandes structures de mémoire (Dictionnaire ou complets La liste de), il serait prudent d'aller lookup ce que les règles exactes.

En ce qui concerne la récupération de la mémoire à la fin du processus, à moins que votre cours d'exécution Win98 ou il équivalent, tout est remis à l'OS à la résiliation. Les seules exceptions sont des choses qui sont inter-processus ouvert et un autre processus a encore la ressource ouverte.

Les objets COM peuvent être tho délicat. Si vous utilisez toujours le IDisposemotif, vous serez en sécurité. Mais j'ai couru à travers quelques assemblées Interop qui mettent en œuvre IDispose. La clé est d'appeler ici Marshal.ReleaseCOMObjectlorsque vous avez terminé avec elle. Les objets COM utilisent encore le comptage de référence standard COM.

Créé 07/08/2008 à 14:17
source utilisateur

voix
6

J'ai trouvé .Net Memory Profiler une très bonne aide lors de la recherche des fuites de mémoire dans .Net. Ce n'est pas libre comme le Microsoft CLR Profiler, mais il est plus rapide et plus au point , à mon avis. UNE

Créé 20/08/2008 à 19:39
source utilisateur

voix
1

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

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

Créé 27/08/2014 à 16:22
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more