2010-01-11 4 views
2

Mon application vient de divulguer 1,5 Go de mémoire. Je suppose que puisque je n'ai pas une tonne de données à ma disposition, je suppose qu'il y a une fuite de mémoire, mais ça pourrait aussi être juste tenir dessus. Je suis actuellement en train d'utiliser perfmon pour recueillir autant d'informations que possible, pour essayer de comprendre ce qui pourrait causer le problème. Je n'ai pas beaucoup de pistes à ce stade, et j'espérais obtenir plus d'indices de la part des gens ici.Déboguer une énorme fuite de mémoire dans l'application

  1. La première chose que je peux dire est que je n'implémente pas IDisposable dans aucune de mes classes. Cependant, je sais que je n'appelle Dispose sur aucun des éléments GUI, comme SolidColorBrush. Comme mon application n'est pas très gourmande en graphiques, je pense que cela ne peut pas causer le problème. Cependant, je vais ajouter les appels nécessaires.

  2. Je ne sais pas si j'utilise d'autres classes dans le framework implémentant IDisposable. J'ai lu un article here on SO sur FxCop. Je l'ai installé et utilisé pour analyser mon assemblage, mais il semble vérifier seulement l'implémentation correcte de mes propres classes d'IDisposable. Existe-t-il un autre outil qui peut me dire TOUTES les classes qui implémentent IDisposable? J'utilise actuellement WF dans mon application, et les WF sont constamment lancés et terminés. Perfmon montre que les fichiers WF se terminent correctement, et j'utilise le mot-clé "using", qui, d'après ce que je comprends, traite de l'élimination appropriée pour moi.

  3. Existe-t-il un moyen simple de savoir si la "fuite" de la mémoire provient d'un code non géré ou géré?

  4. L'application utilisait 77k + poignées au moment où j'ai reçu l'exception MOO.

Des conseils sur la façon de procéder ensuite seraient grandement appréciés. Je prévois de redémarrer l'application et de surveiller les compteurs de performance, et peut-être de supprimer certains appels. Je peux aussi lancer la simulation pour des raisons de comparaison, car dans ce mode, elle ne va pas appeler ma DLL C.

+0

Je viens également d'installer et de faire fonctionner le profileur CLR, et il semble ne jamais vraiment s'attacher à mon processus. Il lance mon application, mais la fenêtre qui dit "attendre l'application pour lancer le Common Language Runtime" reste à l'écran pour toujours. Lorsque je ferme mon application, elle est toujours là. Alors peut-être que ça ne marche pas avec .NET 3.5 après tout. – Dave

+0

Fonctionne avec .NET 3.5. –

+0

J'ai eu ce problème avant aussi, je pense que la solution était de l'exécuter en tant qu'administrateur. –

Répondre

4
+0

en les lisant maintenant! :) Merci! – Dave

+0

Problème n'est pas encore résolu à 100%, mais cette réponse est venu le plus proche et fourni une tonne d'informations utiles pour moi de rechercher et d'apprendre sur des sujets très pertinents. C'était génial! En utilisant ANTS, j'ai pu réduire la fuite à la création de WorkflowRuntime. Même si j'ai créé le runtime avec "using (WorkflowRuntime wr = new WorkflowRuntime()) {}", il y a des fuites énormes de mémoire à chaque fois. Selon un tas de résultats de recherche, ce bug était censé avoir été corrigé à ce jour. Ma "solution" actuelle à des fins de test seulement est d'utiliser un singleton. – Dave

+0

Le singleton n'est pas 100% correct IMO, parce que je dois être capable de différencier les différents flux de travail. Je cours jusqu'à 8 simultanément, et si l'un d'eux rencontre une erreur, j'ai besoin de savoir lequel. Comment pouvez-vous déterminer quel WF a eu l'erreur? C'est peut-être le sujet d'une autre question. :) – Dave

0

Use CLR Profiler pour savoir ce que vous fuyez. Puis réparez-le.

+0

Je viens de poster un commentaire sur ma question il y a quelques minutes - le profileur CLR ne semble pas fonctionner correctement. Il lance mon application, mais attend juste que le CLR soit lancé, apparemment. – Dave

2

Red-Gate a un profileur de mémoire (http://www.red-gate.com/products/ants_memory_profiler/index.htm) qui est extrêmement utile pour ce genre de choses. Je le recommande fortement. Essai de 30 jours.

Randy

+0

Cool, je vais l'installer ensuite. J'avais le profileur de SciTech là-bas à l'origine. J'ai demandé à Red Gate il y a quelques semaines pour une démo personnelle, mais ils ont refusé. :) Je suppose que je vais retrousser mes manches et essayer ça ensuite. – Dave

2

Avant d'aller et d'investir dans des outils, vous devriez essayer de savoir ce qui fuit ...

Vous avez déjà attaché perfmon, et ce qui est grand. Je surveillerais les perfcounters suivants.

processus \ PrivateBytes processus \ Handle Count Process \ NonPagedPool

Mémoire CLR .NET *

Si vos octets privés augmente, ainsi que la mémoire CLR .NET \ BytesInAllHeaps, il pointe vers un fuite contrôlée. ÉTAPES SUIVANTES: Effectuez un cliché de processus et analysez-le à l'aide du profileur CLR ou, à tour de rôle, attachez windbg.exe au processus, chargez l'extension sos dll et analysez votre tas géré à la recherche de fuites. Si les octets privés augmentent, sans augmentation correspondante des compteurs .NET CLR Memory *, cela indique une fuite non gérée. Vous devrez attacher windbg.exe au processus et utiliser l'extension! Heap pour examiner les tas de processus.

Si vous observez un HandleCount croissant de façon monotone ainsi que NonPagedPool, vous avez une fuite de handle - cela peut être du code managé ou du code natif. Vous devrez déterminer quelles poignées fuient - vous pouvez utiliser processmon.exe de sysinternals pour obtenir une liste des handles, et étudier plus avant.

Espérons que cela aide.

+0

Malheureusement, j'ai déjà fermé l'application pour que je puisse essayer le profilage, mais j'ai vérifié la valeur des octets privés et c'était l.5GB. Je n'ai pas ajouté le NonPagedPool, malheureusement. BytesInAllHeaps était également 1,5 Go. Merci pour l'info utile! – Dave

+0

Ok, maintenant je sais que ça vient certainement de mon flux de travail. Je crée l'exécution en utilisant {}, puis en appelant CreateWorkflow et en lui passant une nouvelle instance de mon flux de travail séquentiel.Si j'étais plus intelligent quand j'ai écrit ce code pour la première fois, j'aurais fait de l'exécution du flux de travail un singleton, plutôt que d'en instancier un nouveau à chaque fois. Je vais le faire en premier et voir ce qui se passe. Mais encore, même si je l'ai fait, ne devrait pas utiliser {} a appelé Dispose ??? – Dave

+0

Oups, et pour clarifier, je pense que je devrais créer un pool de runtime WF, car j'en aurai certainement besoin de plus d'un à la fois. – Dave

0

Pas directement répondre à votre question, mais j'utilise toujours Process Explorer qui montre le processus de taille virtuelle, Working Set, Gen 0,1 et 2 collections et octets privés (liés à la mémoire non gérée). Fondamentalement, il s'agit simplement d'une interface utilisateur sympa pour le gestionnaire de tâches Windows et les compteurs de performance. Peut vous aider à observer le comportement lié à la mémoire de votre application.

+0

c'est ce que j'utilise perfmon pour, qui vous donnera les mêmes informations, et il est déjà intégré dans Windows. Ce n'est pas joli, mais la vue du rapport fonctionne très bien IMO. – Dave