.NET5程序w3wp进程非托管内存泄漏,剩余内存去向查询
内存缺口的常见来源
- GC堆预提交未使用内存
.NET GC会以段为单位申请和提交内存,!eeheap输出的GC Heap Size仅统计了实际托管对象占用的内存,不包含已经提交但还未分配对象的段内存。你使用了16个GC堆(服务器GC模式),每个堆都会预申请一定量的提交内存,这部分差值通常是内存缺口的最大来源。 - 未纳入统计的基础内存开销
你之前的统计未包含以下已提交内存:- 线程栈:共234个线程栈,总大小386.375MB
- 镜像加载:所有dll/exe的代码页、资源页提交,总大小170MB
- 其他系统开销:TEB、PEB、系统缓存等,合计约2MB
以上三项合计约558MB,已经占了缺口的近1/4。
- 自定义内存分配器申请的内存
若程序中引入了C/C++/Rust/Go等其他语言编写的模块,它们通常会使用自定义的内存分配器,直接通过VirtualAlloc申请大块内存,不会走Windows标准堆,因此!heap -s统计不到,这部分内存会被归类到!address的<unknown>分类中。 - 内存映射文件
程序直接创建的内存映射文件、系统加载的共享内存、大型文件缓存等,都会占用MEM_MAPPED类型的提交内存,不会被统计到托管或标准非托管堆中。 - .NET其他运行时内存
包括JIT生成的机器码缓存、异步IO缓冲区、Socket收发缓冲区、GC簿记内存、调试器代理内存等,都不会被计入GC堆或Loader堆统计。
排查步骤
- 先统计所有提交内存的分类总和,执行命令:
!address -f:MEM_COMMIT -c:".echo %1 %3"
导出所有提交内存块的类型和大小,计算<unknown>分类的总提交大小,即可定位缺口的核心分布。 - 排查GC堆实际提交总大小,执行命令:
!eeheap -gc
累加所有GC段的总大小,减去已分配对象的798MB,得到GC预提交未使用的内存大小。 - 排查大块未知内存的内容,找到
!address中较大的<unknown>提交内存块,用db [内存地址]查看内容特征,判断是第三方库分配、内存映射文件还是其他运行时内存。
内容的提问来源于stack exchange,提问作者dotnetfly
相关产品推荐
相关产品推荐

