本文内容
本文适用于:✔️.NETCore3.1SDK及更高版本
当应用引用不再须要执行所需任务的对象时,可能会发生显存泄露。引用上述对象会制止垃圾回收器回收使用的显存,这一般会造成性能下滑linux 进程 内存溢出 检测工具,并可能最终引起OutOfMemoryException。
本教程演示怎么使用.NET确诊CLI工具剖析.NETCore应用中的显存泄露。假如所在的操作系统是Windows,则可以使用VisualStudio的显存确诊工具调试显存泄露。
本教程使用一个有意泄露显存的示例应用作为练习。还可以剖析无意中泄露显存的应用。
在本教程中,你将:
先决条件
本教程使用:
本教程假设示例应用和工具已安装并可供使用。
检测托管显存的使用情况
在开始搜集确诊数据以帮助根本诱因引起这些情况之前,请确保实际看见显存泄露(显存使用量)下降。可以使用dotnet-counters工具进行确认。
打开控制台窗口并导航到下载并解压缩示例调试目标的目录。运行目标:
dotnet run
在单独的控制嘉义,找到处理ID:
dotnet-counters ps
输出应如下所示:
4807 DiagnosticScena /home/user/git/samples/core/diagnostics/DiagnosticScenarios/bin/Debug/netcoreapp3.0/DiagnosticScenarios
现使用dotnet-counters工具检测托管显存的使用情况。--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
重点介绍此行:
GC Heap Size (MB) 4
启动后,可以看见托管堆显存为4MB。
如今,转入URL:5001/api/diagscenario/memleak/20000。
请注意,显存使用量已降低到30MB。
GC Heap Size (MB) 30
通过监视显存使用情况,可以确定显存正在下降或泄露。下一步是搜集显存剖析的适当数据。
生成显存轮询
剖析可能的显存泄露时linux qq,须要访问应用的显存堆来剖析显存内容。查看对象之间的关系,可以创建关于显存未释放的缘由的理论。常见的确诊数据源是Windows上的显存轮询或Linux上的等效核心轮询。若要生成.NETCore应用程序轮询,可使用dotnet-dump工具。
使用之前启动的示例调试目标linux 进程 内存溢出 检测工具,运行以下命令以生成Linux核心轮询:
dotnet-dump collect -p 4807
结果是坐落同一文件夹中的核心轮询。
Writing minidump with heap to ./core_20190430_185145
Complete
注意
为了随时间推移进行比较,让原始进程在搜集第一个存贮后继续运行,并采用相同的方法搜集第二个存贮。之后,你将在一段时间内有两个存贮,你可以比较这种轮询,以查看显存使用量的下降位置。
重新启动失败的进程
搜集轮询后,你应当有足够的信息来确诊失败的进程。假如失败的进程在生产服务器上运行,如今是通过重新启动进程进行短期修正的理想时机。
在本教程中,你已然完成了示例调试目标,如今可以将其关掉。导航到启动服务器的终端并按Ctrl+C。
剖析核心轮询
生成核心轮询后,请使用dotnet-dump工具剖析轮询:
dotnet-dump analyze core_20190430_185145
其中core_20190430_185145是要剖析的核心轮询的名称。
注意
假如你看见报错“找不到libdl.so”,则可能须要安装libc6-dev包。有关详尽信息,请参阅Linux上.NETCore的先决条件。
此时会显示一个提示,可在其中输入SOS命令。一般,首先要查看的是托管堆的整体状态:
> 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
可在此处见到大多数对象是String或Customer对象。
可以使用方式表(MT)再度使用dumpheap命令来获取所有String实例的列表:
> 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
如今可以对System.String实例使用gcroot命令,以查看对象的根方法和缘由。请耐心等待,由于对于30MB的堆,此命令须要几分钟的时间:
> 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.
可以看见String由Customer对象直接保存,并由CustomerCache对象间接保存。
可以继续轮询对象,以查看大多数String对象是否遵守类似的模式。此时,调查会提供足够的信息来确定代码中的根本缘由。
可通过此常规过程确定主要显存泄露源。
清除资源
在本教程中,你已启动一个示例Web服务器。此服务器应已关掉arm linux,如部份所述。
还可以删掉已创建的轮询文件。
请参阅后续步骤
调试.NETCore中的高CPU