【发布时间】:2012-09-25 10:55:22
【问题描述】:
故事:
我们在 .NET 2.0 应用程序中面临非托管内存泄漏。启动后的进程消耗大约 150MB(其中大部分是 .NET 托管、对象状态等)。 运行大约 12 小时后,进程消耗了 800MB,接下来的 12 小时后,进程有大约 1.8GB 的 RAM。 我刚刚尝试了 JetBrains .NET Memory Profiler、ANTS、.NET Memory Profiler(以及市场上可能有的 2 个下一个 mem 配置文件),这些都没有帮助我,因为我后来检测到我们的进程在未管理的非托管区域中消耗了那么多内存。为了检测到这一点,我使用了带计数器的 Perf 监视器:Private Bytes(Process) 和 # Bytes in All Heaps (.NET CLR Memory),其中 Private Bytes 消耗了进程分配的所有内存的大约 90%。这就是我切换到非托管调试的原因。
调试诊断: 所以我在进程上运行 debugdiag 并获得完整转储,这是它的快照:
mscorwks.dll(一个已知的 Windows 内存管理器)负责 781,73 MB 的未完成分配。这些分配 似乎源自以下模块和 功能:
ntdll.dll(一个已知的 Windows 内存管理器)负责 98,24 MB 的未完成分配。这些分配似乎源自以下模块和功能:
按分配计数排名前 4 位的函数
- mscorwks!EEHeapAlloc+15b -- 80 957 个分配
- mscorwks!CLRMapViewOfFileEx+4a -- 4 171 个分配
按分配大小排列的前 4 个函数
- mscorwks!EEVirtualAlloc+15b -- 117,50 MB
- mscorwks!EEHeapAlloc+15b -- 15,03 MB
发现有趣的日志:
功能详情
Function mscorwks!EEVirtualAlloc+15b
- 分配类型虚拟内存分配
- 分配计数 1471 个分配
- 分配大小 117,50 MBytes
- 泄漏概率 73%
Function mscorwks!EEHeapAlloc+15b
- 分配类型堆分配
- 分配计数 80957 个分配
- 分配大小 15,03 MBytes
- 泄漏概率 72%
Function mscorwks!CExecutionEngine::CheckThreadState+fe
- 分配类型堆分配
- 堆句柄 0x00000000`00000000
- 分配计数 2 个分配
- 分配大小 304 字节
- 泄漏概率 98%
Function mscorwks!CLRMapViewOfFileEx+4a
- 分配类型虚拟内存分配
- 分配计数 4171 个分配
- 分配大小 0 字节
- 泄漏概率 73%
我希望有人将我推向正确的方向,我如何从这个转储中找到内存泄漏?我能够将转储加载到 windbg 并运行标准的 windbg 命令集,但我不知道哪个是能够隔离泄漏的正确命令。
如果有人想提供帮助,我可以提供完整转储。
【问题讨论】:
-
这里有一些可能有用的信息? blogs.msdn.com/b/tess/archive/2009/10/09/…您是否在代码中使用了任何您可能不会清理的 COM 对象?
-
Joe:已经和其他 20 多岁的人一起阅读这篇文章,但仍然不知道在哪里以及如何找到泄漏。我有来自 DebugDiag 的详细日志,但是当我不知道如何“阅读”它时它是无用的:-|
-
我建议您避免关注非托管方面,除非您的应用程序进行主要的非托管内存操作。在 .NET 应用程序中,我看到的内存问题的主要原因是迄今为止意外的引用 - 未删除事件处理程序是主要原因。更多在下面的答案中。
-
私有字节意味着内存不与其他进程共享。托管堆不在进程之间共享,因此如果托管堆很大,私有字节会相应增长。根据您的描述,我不清楚您是否在所有堆中看到大量的私有字节和少量的 # 字节。如果这两个数字都很大,那么您正在查看托管内存。
-
我会试一试的。你能把转储上传到某个地方并分享链接吗?
标签: c# memory-leaks windbg