mscorwks中的非托管内存泄漏有助于分析

时间:2012-10-04 11:53:28

标签: c# memory-leaks windbg

故事:

我们在.NET 2.0应用程序中面临非托管内存泄漏。启动后的进程消耗大约150MB(大部分是.NET托管,对象状态等)。 经过大约12个小时的运行过程消耗高达800MB,在接下来的12个小时后,进程大约有1.8GB的RAM。 我刚试过JetBrains .NET内存分析器,ANTS,.NET内存分析器(以及市场上可能有的2个下一个内存配置文件)这些都没有帮助我,因为我后来检测到我们的进程消耗了非托管区域中未管理的大量内存。为了检测这一点,我使用了具有计数器的Perf监视器:私有字节(进程)和所有堆中的#字节(.NET CLR内存),其中专用字节消耗了进程分配的所有内存的大约90%。这就是我切换到非托管调试的原因。

DebugDiag资料: 所以我在进程上运行debugdiag并获得完全转储,这里是它的快照:

  • mscorwks.dll(一个已知的Windows内存管理器)负责 781,73 MBytes的未完成分配。这些分配 似乎源自以下模块和 (多个)功能:

  • ntdll.dll(一个已知的Windows内存管理器)负责98,24 MB的未完成分配。这些分配似乎源自以下模块和功能:

按分配计数排名前4位的职能

  • mscorwks!EEHeapAlloc + 15b - 80 957分配
  • mscorwks!CLRMapViewOfFileEx + 4a - 4 171分配

按分配大小排名前4位的职能

  • mscorwks!EEVirtualAlloc + 15b - 117,50 MBytes
  • mscorwks!EEHeapAlloc + 15b - 15,03 MBytes

找到有趣的日志:

功能详情

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%

我希望有人向我推进正确的方向如何从这个转储中发现内存泄漏?我能够将dump装入windbg并运行标准的windbg命令集,但我不知道哪一个是能够隔离泄漏的正确命令。

如果有人想帮助我,我可以提供完全转储。

3 个答案:

答案 0 :(得分:3)

查看转储文件,它似乎是一个托管泄漏,只是在托管堆上。转储显示托管堆非常小,但加载器堆为1 GB。该过程有超过35000个动态组件。我查看了其中的一些,它们似乎是序列化(XML和二进制)。看一下这个blog post。它描述了一个类似的问题。

答案 1 :(得分:1)

我最喜欢调试.NET和Silverlight内存泄漏的方法是使用SOS扩展。请参阅此处以获取快速演练:http://blogs.msdn.com/b/ricom/archive/2004/12/10/279612.aspx

我通常做的是:

  1. !DumpHeap -stat获取内存中存在的对象列表;这通常表明问题的根源(例如,如果我看到一百万个微小的物体,只能使用一次并扔掉)。
  2. 一旦我知道什么类型的对象导致它,我使用!DumpHeap转储这些对象的列表并随机获取其中几个的根(!GCRoot)。这通常表示哪个对象意外地持有对漏洞对象的引用。
  3. 这假设您正在处理托管内存泄漏(引用保留在您不期望的位置)。如果您正在处理非托管内存泄漏,那将无济于事,但除非您的应用程序执行大量手动非托管内存管理(例如P / Invoke的对象编组),否则这种情况就不太可能了。

答案 2 :(得分:0)

使用弱引用可能会减少内存使用量http://en.wikipedia.org/wiki/Weak_reference ..这是非常一般的,但一旦它为我节省了几乎几百GB