An article teaches you how to troubleshoot. NET memory leaks
- 2021-12-04 09:56:33
Memory leak usually means that after some objects of an application complete its life cycle, they are accidentally referenced by other objects, which leads to the failure of subsequent gc to recycle them. In the long run, it will lead to the degradation of program performance and potential OutOfMemoryException.
In this article, we use a memory leak tool to analyze the memory leak of. NET Core program. If the program runs on windows, we can directly use Visual Studio for diagnosis.
Check managed memory usage
Before you start analyzing memory leaks, you must have evidence that there is a memory leak, which can be verified by looking at various indicators of the application with dotnet-counters.
Run the program
Find out the pid of the program,
dotnet-counters ps 4807 DiagnosticScena /home/user/git/samples/core/diagnostics/DiagnosticScenarios/bin/Debug/netcoreapp3.0/DiagnosticScenarios
Start the monitor using monitor, where--refresh-interval denotes the refresh interval
dotnet-counters monitor --refresh-interval 1 -p 4807 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
Focus on the GC Heap Size (MB) index under 1. You can see that the current GC heap memory is 4M after the program starts. Open the link: https://localhost: 5001/api/diagscenario/memleak/20000, and then look at the GC heap memory. You can see that 30M is reached under 1.
GC Heap Size (MB) 30
By comparing the use of memory, we can say with confidence that the memory leaks.
Generate an dump file
If you want to analyze the memory leak of your program, you must first have access to the GC heap, so that you can analyze the relationship between heap memory and objects, and then you can boldly guess why the memory has not been released. To generate the dump file of the. NET Core program, you can use the dotnet-dump tool.
dotnet-dump collect -p 4807 Writing minidump with heap to ./core_20190430_185145 Complete
Analysis of core dump
You can then parse the generated dump file using dotnet-dump analyze.
dotnet-dump analyze core_20190430_185145
Here core_20190430_185145 is the name of dump you want to analyze. It is worth mentioning that if you encounter libdl. so cannot be found error, it is recommended to install libc6-dev package package under 1.
First, we look at the statistical list of all objects on the managed heap through the sos command.
> 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
From the output, most of them are String and Customer objects, and then you can get all the instance objects under the method table through mt parameters.
> dumpheap -mt 00007faddaa50f90 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
You can use it next! gcroot to see who holds a certain string.
> gcroot -all 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.
From the reference chain of string, it is held by CustomerCache, and then you can look for problems in the code.
Original link: https://docs.microsoft.com/en-us/dotnet/core/diagnostics/debug-memory-leak