Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
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 handledningen kommer du att:
- Granska hanterad minnesanvändning med dotnet-räknare.
- Generera en dumpfil.
- Analysera minnesanvändningen med hjälp av dumpfilen.
Förutsättningar
Instruktionen 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.
Handledningen förutsätter att exempelapparna och verktygen är installerade och redo att användas.
Om din app kör en version av .NET som är äldre än .NET 9 ser utdatagränssnittet för dotnet-counters något annorlunda ut. se dotnet-counters för mer information.
Granska hanterad minnesanvändning
Innan du börjar samla in diagnostikdata för att hjälpa till att identifiera grundorsaken till det här scenariot, måste du se till att du verkligen observerar 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 packade upp sample debug target. Kör uppgiften:
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
Anmärkning
Om föregående kommando inte fungerar eller inte hittas måste du förmodligen installera dotnet-counters verktyget först. Använd följande kommando:
dotnet tool install --global dotnet-counters
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
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
Fokusera på den här raden:
dotnet.gc.last_collection.memory.committed_size (By) 4,296,704
Du kan se att det hanterade heap-minnet ä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 över 20 MB.
dotnet.gc.last_collection.memory.committed_size (By) 21,020,672
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 med hjälp av det tidigare startade exempelfelsökningsmålet för att generera en Linux-kärndumpning:
dotnet-dump collect -p 4807
Resultatet är en kärndump som finns i samma mapp.
Writing minidump with heap to ./core_20190430_185145
Complete
Anmärkning
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 Exempel för felsökningsmål 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.
Anmärkning
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 denna tidpunkt har undersökningen tillhandahållit tillräckligt med information för att identifiera grundorsaken 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 handledningen startade du en exempel-webbserver. 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