Felsöka en minnesläcka i .NET
Den här artikeln gäller för: ✔️ .NET Core 3.1 SDK och senare versioner
Minnet kan läcka när appen refererar till objekt som den inte längre behöver utföra den önskade uppgiften. Om du refererar till dessa objekt hindras skräpinsamlaren från att frigöra det minne som används. Det kan leda till att prestandaförsämring och ett OutOfMemoryException undantag utlöses.
Den här självstudien visar verktygen för att analysera en minnesläcka i en .NET-app med hjälp av CLI-verktygen för .NET-diagnostik. Om du använder Windows kanske du kan använda Visual Studios verktyg för minnesdiagnostik för att felsöka minnesläckan.
I den här självstudien används en exempelapp som avsiktligt läcker minne som en övning. Du kan också analysera appar som oavsiktligt läcker minne.
I den här självstudien kommer vi att:
- Granska hanterad minnesanvändning med dotnet-räknare.
- Generera en dumpfil.
- Analysera minnesanvändningen med hjälp av dumpfilen.
Förutsättningar
Självstudien använder:
- .NET Core 3.1 SDK eller en senare version.
- dotnet-counters för att kontrollera hanterad minnesanvändning.
- dotnet-dump för att samla in och analysera en dumpfil (inkluderar SOS-felsökningstillägget).
- Ett exempel på en felsökningsmålapp som ska diagnostiseras.
Självstudien förutsätter att exempelapparna och verktygen är installerade och redo att användas.
Granska hanterad minnesanvändning
Innan du börjar samla in diagnostikdata för att hjälpa rotorsaken till det här scenariot måste du se till att du faktiskt ser en minnesläcka (ökad minnesanvändning). Du kan använda verktyget dotnet-counters för att bekräfta detta.
Öppna ett konsolfönster och navigera till katalogen där du laddade ned och packa upp felsökningsmålet. Kör målet:
dotnet run
Från en separat konsol hittar du process-ID:t:
dotnet-counters ps
Utdata bör likna:
4807 DiagnosticScena /home/user/git/samples/core/diagnostics/DiagnosticScenarios/bin/Debug/netcoreapp3.0/DiagnosticScenarios
Kontrollera nu den hanterade minnesanvändningen med verktyget dotnet-counters . --refresh-interval
Anger antalet sekunder mellan uppdateringarna:
dotnet-counters monitor --refresh-interval 1 -p 4807
Liveutdata bör se ut ungefär så här:
Press p to pause, r to resume, q to quit.
Status: Running
[System.Runtime]
# of Assemblies Loaded 118
% Time in GC (since last GC) 0
Allocation Rate (Bytes / sec) 37,896
CPU Usage (%) 0
Exceptions / sec 0
GC Heap Size (MB) 4
Gen 0 GC / sec 0
Gen 0 Size (B) 0
Gen 1 GC / sec 0
Gen 1 Size (B) 0
Gen 2 GC / sec 0
Gen 2 Size (B) 0
LOH Size (B) 0
Monitor Lock Contention Count / sec 0
Number of Active Timers 1
ThreadPool Completed Work Items / sec 10
ThreadPool Queue Length 0
ThreadPool Threads Count 1
Working Set (MB) 83
Fokusera på den här raden:
GC Heap Size (MB) 4
Du kan se att det hanterade heapminnet är 4 MB direkt efter start.
Gå nu till URL:en https://localhost:5001/api/diagscenario/memleak/20000
.
Observera att minnesanvändningen har ökat till 30 MB.
GC Heap Size (MB) 30
Genom att titta på minnesanvändningen kan du på ett säkert sätt säga att minnet växer eller läcker. Nästa steg är att samla in rätt data för minnesanalys.
Generera minnesdump
När du analyserar möjliga minnesläckor behöver du åtkomst till appens minneshög för att analysera minnesinnehållet. När du tittar på relationer mellan objekt skapar du teorier om varför minnet inte frigörs. En vanlig diagnostikdatakälla är en minnesdump i Windows eller motsvarande kärndump i Linux. Om du vill generera en dump av ett .NET-program kan du använda verktyget dotnet-dump .
Kör följande kommando för att generera en Linux-kärndumpning med hjälp av exempelfelsökningsmålet som startades tidigare:
dotnet-dump collect -p 4807
Resultatet är en kärndump som finns i samma mapp.
Writing minidump with heap to ./core_20190430_185145
Complete
Kommentar
För en jämförelse över tid kan du låta den ursprungliga processen fortsätta köras efter insamling av den första dumpen och samla in en andra dump på samma sätt. Du skulle då ha två dumpar under en tidsperiod som du kan jämföra för att se var minnesanvändningen växer.
Starta om den misslyckade processen
När dumpen har samlats in bör du ha tillräckligt med information för att diagnostisera den misslyckade processen. Om den misslyckade processen körs på en produktionsserver är det nu den perfekta tiden för kortsiktig reparation genom att starta om processen.
I den här självstudien är du nu klar med felsökningsmålet Exempel och du kan stänga det. Gå till terminalen som startade servern och tryck på Ctrl+C.
Analysera kärndumpningen
Nu när du har genererat en kärndump använder du verktyget dotnet-dump för att analysera dumpen:
dotnet-dump analyze core_20190430_185145
Var core_20190430_185145
är namnet på den kärndump som du vill analysera.
Kommentar
Om du får ett felmeddelande om att libdl.so inte kan hittas kan du behöva installera libc6-dev-paketet . Mer information finns i Krav för .NET på Linux.
Du får en fråga där du kan ange SOS-kommandon . Vanligtvis är det första du vill titta på det övergripande tillståndet för den hanterade heapen:
> 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
Här kan du se att de flesta objekt är antingen String
eller Customer
objekt.
Du kan använda dumpheap
kommandot igen med metodtabellen (MT) för att hämta en lista över alla String
instanser:
> 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
Nu kan du använda gcroot
kommandot på en System.String
instans för att se hur och varför objektet är rotat:
> 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.
Du kan se att String
är direkt innehas av objektet Customer
och indirekt innehas av ett CustomerCache
objekt.
Du kan fortsätta att dumpa objekt för att se att de flesta String
objekt följer ett liknande mönster. Vid den här tidpunkten tillhandahöll undersökningen tillräckligt med information för att identifiera rotorsaken i koden.
Med den här allmänna proceduren kan du identifiera källan till större minnesläckor.
Rensa resurser
I den här självstudien startade du en exempelwebbserver. Den här servern bör ha stängts av enligt beskrivningen i avsnittet Starta om den misslyckade processen .
Du kan också ta bort dumpfilen som skapades.
Se även
- dotnet-trace till listprocesser
- dotnet-räknare för att kontrollera hanterad minnesanvändning
- dotnet-dump för att samla in och analysera en dumpfil
- dotnet/diagnostik
- Använda Visual Studio för att felsöka minnesläckor