dotnet-dump是分析.net 6+托管内存问题最轻量、最可靠的首选工具,但仅对.net core 3.1+真正开箱即用;对.net framework或.net 5及更早版本大概率报错或返回空结果,需确认dump来自.net 6+运行时、架构匹配且使用--type heap跨平台兼容。

直接上结论:dotnet-dump 是分析 .NET 6+ 托管内存问题最轻量、最可靠的首选工具,但它只对 .NET Core 3.1 及以后(尤其是 .NET 6+)真正开箱即用;对 .NET Framework 或 .NET 5 及更早版本,它大概率报错或返回空结果,别硬试。
dotnet-dump analyze 进入交互后卡住或命令无效
这不是网络或权限问题,而是运行时环境没对齐。常见现象包括:clrstack -all 返回空、dumpheap -stat 报 Failed to load data access DLL、或命令执行后长时间无响应。
- 必须确认 dump 文件来自 .NET 6+ 运行时——用
dotnet-dump analyze myapp.dmp后第一行输出应含Runtime: .NET 6.0或更高;若显示.NET Core 3.1且命令异常,优先降级到dotnet-sos+ WinDbg Preview - Windows 上采集的
--type Fulldump 在 Linux/macOS 下无法分析,反之亦然;跨平台只支持--type heap生成的文件 - 64 位进程 dump 必须用 64 位 dotnet-dump 工具链;若你用的是 x86 SDK 安装的全局工具,会静默失败——检查
dotnet --list-runtimes输出架构是否匹配 - 不依赖 PDB,但若 dump 来自 Release 编译且未保留调试信息,
clrstack可能只显示[External Code],此时需回退到源码环境重编译或改用 Visual Studio 打开
dumpheap -stat 排名靠前的类型不等于泄漏源
看统计表只是起点,不是终点。比如 System.String 占比 40%,不代表它就是泄漏点——它可能只是正常日志缓存,也可能背后是 Dictionary<string object></string> 持有大量键值对未释放。
- 先记下可疑类型全名(如
MyApp.Data.CacheEntry),再执行dumpheap -type MyApp.Data.CacheEntry查具体实例数和地址 - 挑一个对象地址(如
00007f9a12345678),运行gcroot 00007f9a12345678;重点看输出里是否含Static Variables、Finalizer Queue或HandleTable - 若
gcroot显示根在System.Threading.Timer回调里,说明可能被定时器强引用;若在EventWaitHandle或ManualResetEvent上挂起,要查同步等待逻辑是否漏了Set() -
dumpheap -min 85000单独查 LOH,如果byte[]实例数远高于预期,立刻检查文件读取、Base64 解码、JSON 序列化等是否产生短命大对象——它们不会被频繁回收,容易堆积
对比多个 dump 时为什么 dumpheap -stat 数值不一致
不是工具不准,是默认统计口径不同:dumpheap -stat 统计的是“当前存活对象”,而 GC 状态受转储触发时机影响极大。同一进程连续两次采集,若中间发生过 GC,数字就不可比。
- 务必用相同
--type参数采集(推荐统一用--type heap),避免 mini 和 full 混用 - 采集前手动触发 GC:在目标进程里插入
GC.Collect(); GC.WaitForPendingFinalizers();(仅限调试环境),或用dotnet-gcdump配合--collect-quick更精准 - 导出为文本再比对:执行
dotnet-dump analyze myapp1.dmp -c "dumpheap -stat" > stat1.txt,同理导出 stat2.txt,用diff stat1.txt stat2.txt查增量类型 - 警惕
String和Byte[]的“假增长”:它们常因日志、HTTP body 缓存临时膨胀,真正该盯的是自定义类(如OrderProcessor、SessionState)的实例数是否持续上升
最易被忽略的一点:dotnet-dump 不解析非托管堆。如果你看到内存持续上涨但托管堆稳定,问题大概率在 P/Invoke 调用、未释放的 GDI 句柄、或第三方 native 库——这时候得切到 perf(Linux)、Process Explorer(Windows)或 dotnet-trace 查非托管分配热点。










