Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de changer d’annuaire.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer d’annuaire.
Cet article s’applique à : ✔️ SDK .NET Core 3.1 et versions ultérieures
La mémoire peut s’écouler lorsque votre application référence des objets qu’elle n’a plus besoin d’effectuer la tâche souhaitée. Faire référence à ces objets empêche le garbage collector de récupérer la mémoire utilisée. Cela peut entraîner une dégradation des performances et le déclenchement d’une exception OutOfMemoryException.
Ce tutoriel montre les outils permettant d’analyser une fuite de mémoire dans une application .NET à l’aide des outils CLI des diagnostics .NET. Si vous êtes sur Windows, vous pouvez utiliser les outils de diagnostic de mémoire de Visual Studio pour déboguer la fuite de mémoire.
Ce tutoriel utilise une application d'exemple qui provoque intentionnellement une fuite de mémoire, en tant qu'exercice. Vous pouvez également analyser des applications qui fuient involontairement la mémoire.
Dans ce tutoriel, vous allez :
- Examinez l’utilisation de la mémoire managée avec dotnet-counters.
- Créer un fichier image mémoire.
- Analysez l’utilisation de la mémoire à l’aide du fichier de vidage.
Conditions préalables
Le tutoriel utilise :
- Sdk .NET Core 3.1 ou version ultérieure.
- dotnet-counters pour vérifier l’utilisation de la mémoire managée.
- dotnet-dump pour collecter et analyser un fichier de vidage (inclut l’extension de débogage SOS).
- Exemple d’échantillon d’application cible de débogage à diagnostiquer.
Le didacticiel part du principe que les exemples d’applications et d’outils sont installés et prêts à être utilisés.
Si votre application exécute une version de .NET antérieure à .NET 9, l’interface utilisateur de sortie des compteurs dotnet est légèrement différente ; pour plus d’informations, consultez dotnet-counters .
Examiner l’utilisation de la mémoire managée
Avant de commencer à collecter des données de diagnostic pour faciliter la cause racine de ce scénario, assurez-vous que vous voyez réellement une fuite de mémoire (croissance de l’utilisation de la mémoire). Vous pouvez utiliser l’outil dotnet-counters pour confirmer cela.
Ouvrez une fenêtre de console et accédez au répertoire où vous avez téléchargé et décompressé l’exemple de cible de débogage. Exécutez la cible :
dotnet run
À partir d’une console distincte, recherchez l’ID de processus :
dotnet-counters ps
La sortie doit ressembler à ce qui suit :
4807 DiagnosticScena /home/user/git/samples/core/diagnostics/DiagnosticScenarios/bin/Debug/netcoreapp3.0/DiagnosticScenarios
Remarque
Si la commande précédente ne fonctionne pas ou n’est pas trouvée, vous devez d’abord installer l’outil dotnet-counters . Utilisez la commande suivante :
dotnet tool install --global dotnet-counters
À présent, vérifiez l’utilisation de la mémoire managée avec l’outil dotnet-counters . Spécifie --refresh-interval le nombre de secondes entre les actualisations :
dotnet-counters monitor --refresh-interval 1 -p 4807
La sortie dynamique doit être similaire à :
Press p to pause, r to resume, q to quit.
Status: Running
Name Current Value
[System.Runtime]
dotnet.assembly.count ({assembly}) 111
dotnet.gc.collections ({collection})
gc.heap.generation
------------------
gen0 1
gen1 0
gen2 0
dotnet.gc.heap.total_allocated (By) 4,431,712
dotnet.gc.last_collection.heap.fragmentation.size (By)
gc.heap.generation
------------------
gen0 803,576
gen1 15,456
gen2 0
loh 0
poh 0
dotnet.gc.last_collection.heap.size (By)
gc.heap.generation
------------------
gen0 811,960
gen1 1,214,720
gen2 0
loh 0
poh 24,528
dotnet.gc.last_collection.memory.committed_size (By) 4,296,704
dotnet.gc.pause.time (s) 0.003
dotnet.jit.compilation.time (s) 0.329
dotnet.jit.compiled_il.size (By) 120,212
dotnet.jit.compiled_methods ({method}) 1,202
dotnet.monitor.lock_contentions ({contention}) 2
dotnet.process.cpu.count ({cpu}) 22
dotnet.process.cpu.time (s)
cpu.mode
--------
system 0.344
user 0.344
dotnet.process.memory.working_set (By) 64,331,776
dotnet.thread_pool.queue.length ({work_item}) 0
dotnet.thread_pool.thread.count ({thread}) 0
dotnet.thread_pool.work_item.count ({work_item}) 7
dotnet.timer.count ({timer}) 0
Concentrez-vous sur cette ligne :
dotnet.gc.last_collection.memory.committed_size (By) 4,296,704
Vous pouvez voir que la mémoire du tas managée est de 4 Mo juste après le démarrage.
À présent, accédez à l’URL https://localhost:5001/api/diagscenario/memleak/20000.
Notez que l’utilisation de la mémoire a augmenté de plus de 20 Mo.
dotnet.gc.last_collection.memory.committed_size (By) 21,020,672
En regardant l’utilisation de la mémoire, vous pouvez dire en toute sécurité que la mémoire est en croissance ou en fuite. L’étape suivante consiste à collecter les données appropriées pour l’analyse de la mémoire.
Générer un vidage de mémoire
Lors de l’analyse des fuites de mémoire possibles, vous devez accéder au tas de mémoire de l’application pour analyser le contenu de la mémoire. En examinant les relations entre les objets, vous créez des théories sur la raison pour laquelle la mémoire n’est pas libérée. Une source de données de diagnostic courante est un vidage de mémoire sur Windows ou le vidage de cœur équivalent sur Linux. Pour générer un vidage d’une application .NET, vous pouvez utiliser l’outil dotnet-dump .
À l’aide de l’échantillon de cible de débogage précédemment démarré, exécutez la commande suivante pour générer une image mémoire principale Linux :
dotnet-dump collect -p 4807
Le résultat est un core dump situé dans le même dossier.
Writing minidump with heap to ./core_20190430_185145
Complete
Remarque
Pour une comparaison au fil du temps, laissez le processus original continuer à fonctionner après la collecte du premier vidage et recueillez un deuxième vidage de la même manière. Vous aurez alors deux images mémoire sur une période de temps que vous pouvez comparer pour voir où l’utilisation de la mémoire augmente.
Redémarrer le processus ayant échoué
Une fois l’image mémoire collectée, vous devez disposer d’informations suffisantes pour diagnostiquer l’échec du processus. Si le processus ayant échoué s’exécute sur un serveur de production, il est maintenant le temps idéal pour la correction à court terme en redémarrant le processus.
Dans ce tutoriel, vous avez maintenant terminé avec l’exemple de cible de débogage et vous pouvez le fermer. Accédez au terminal qui a démarré le serveur, puis appuyez sur Ctrl+C.
Analyser l’image mémoire principale
Maintenant que vous disposez d’un core dump généré, utilisez l’outil dotnet-dump pour analyser le core dump :
dotnet-dump analyze core_20190430_185145
Où core_20190430_185145 est le nom du core dump que vous souhaitez analyser.
Remarque
Si vous constatez une erreur indiquant que libdl.so est introuvable, vous devrez peut-être installer le package libc6-dev . Pour plus d’informations, consultez Conditions préalables pour .NET sur Linux.
Vous serez invité à saisir des commandes SOS dans un champ. Généralement, la première chose que vous souhaitez examiner est l’état global du tas managé :
> dumpheap -stat
Statistics:
MT Count TotalSize Class Name
...
00007f6c1eeefba8 576 59904 System.Reflection.RuntimeMethodInfo
00007f6c1dc021c8 1749 95696 System.SByte[]
00000000008c9db0 3847 116080 Free
00007f6c1e784a18 175 128640 System.Char[]
00007f6c1dbf5510 217 133504 System.Object[]
00007f6c1dc014c0 467 416464 System.Byte[]
00007f6c21625038 6 4063376 testwebapi.Controllers.Customer[]
00007f6c20a67498 200000 4800000 testwebapi.Controllers.Customer
00007f6c1dc00f90 206770 19494060 System.String
Total 428516 objects
Ici, vous pouvez voir que la plupart des objets sont soit String, soit Customer.
Vous pouvez utiliser à nouveau la dumpheap commande avec la table de méthodes (MT) pour obtenir la liste de toutes les String instances :
> dumpheap -mt 00007f6c1dc00f90
Address MT Size
...
00007f6ad09421f8 00007faddaa50f90 94
...
00007f6ad0965b20 00007f6c1dc00f90 80
00007f6ad0965c10 00007f6c1dc00f90 80
00007f6ad0965d00 00007f6c1dc00f90 80
00007f6ad0965df0 00007f6c1dc00f90 80
00007f6ad0965ee0 00007f6c1dc00f90 80
Statistics:
MT Count TotalSize Class Name
00007f6c1dc00f90 206770 19494060 System.String
Total 206770 objects
Vous pouvez maintenant utiliser la gcroot commande sur une System.String instance pour voir comment et pourquoi l’objet est rooté :
> gcroot 00007f6ad09421f8
Thread 3f68:
00007F6795BB58A0 00007F6C1D7D0745 System.Diagnostics.Tracing.CounterGroup.PollForValues() [/_/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs @ 260]
rbx: (interior)
-> 00007F6BDFFFF038 System.Object[]
-> 00007F69D0033570 testwebapi.Controllers.Processor
-> 00007F69D0033588 testwebapi.Controllers.CustomerCache
-> 00007F69D00335A0 System.Collections.Generic.List`1[[testwebapi.Controllers.Customer, DiagnosticScenarios]]
-> 00007F6C000148A0 testwebapi.Controllers.Customer[]
-> 00007F6AD0942258 testwebapi.Controllers.Customer
-> 00007F6AD09421F8 System.String
HandleTable:
00007F6C98BB15F8 (pinned handle)
-> 00007F6BDFFFF038 System.Object[]
-> 00007F69D0033570 testwebapi.Controllers.Processor
-> 00007F69D0033588 testwebapi.Controllers.CustomerCache
-> 00007F69D00335A0 System.Collections.Generic.List`1[[testwebapi.Controllers.Customer, DiagnosticScenarios]]
-> 00007F6C000148A0 testwebapi.Controllers.Customer[]
-> 00007F6AD0942258 testwebapi.Controllers.Customer
-> 00007F6AD09421F8 System.String
Found 2 roots.
Vous pouvez voir que la propriété String est directement détenue par l’objet Customer et indirectement détenue par un CustomerCache objet.
Vous pouvez continuer à vider les objets pour voir que la plupart des String objets suivent un modèle similaire. À ce stade, l’enquête a fourni suffisamment d’informations pour identifier la cause racine dans votre code.
Cette procédure générale vous permet d’identifier la source des fuites de mémoire majeures.
Nettoyer les ressources
Dans ce tutoriel, vous avez démarré un exemple de serveur web. Ce serveur doit avoir été arrêté comme expliqué dans la section Redémarrer le processus ayant échoué .
Vous pouvez également supprimer le fichier image mémoire créé.
Voir aussi
- dotnet-trace pour répertorier les processus
- dotnet-counters pour vérifier l’utilisation de la mémoire managée
- dotnet-dump pour collecter et analyser un fichier de vidage
- dotnet/diagnostics
- Utiliser Visual Studio pour déboguer les fuites de mémoire