C# mscorwks帮助分析中的非托管内存泄漏

C# mscorwks帮助分析中的非托管内存泄漏,c#,memory-leaks,windbg,C#,Memory Leaks,Windbg,故事: 在.NET 2.0应用程序中,我们面临非托管内存泄漏。启动后的进程消耗大约150MB(大部分是.NET管理的,对象状态等等)。 在大约12小时的运行后,进程消耗了800MB的内存,而在接下来的12小时后,进程拥有大约1.8GB的内存。 我刚刚试过JetBrains.NET内存分析器、ANTS、.NET内存分析器(以及市场上可能提供的2个next mem配置文件),这些都没有帮助我,因为我后来发现我们的进程在非托管区域消耗了大量内存,而非托管区域。为了检测这一点,我使用了带有计数器的Per

故事:

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

调试诊断: 所以我在进程上运行debugdiag并获得完整转储,下面是它的快照:

  • mscorwks.dll(已知的Windows内存管理器)负责 价值781,73兆字节的未分配资金。这些拨款 似乎来自以下模块,并且 职能:

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

按分配计数排列的前4项功能

  • mscorwks!EEHeapAlloc+15b--80957分配
  • mscorwks!CLRMAPVIEWOFFILEX+4a--4171分配
按分配大小排列的前4项功能

  • mscorwks!EEVirtualAlloc+15b--117,50兆字节
  • mscorwks!EEHeapAlloc+15b--15,03兆字节
找到有趣的日志:

功能详细信息

函数mscorwks!EEVirtualAlloc+15b

  • 分配类型虚拟内存分配
  • 分配计数1471分配
  • 分配大小117,50 MB
  • 泄漏概率73%
函数mscorwks!EEHeapAlloc+15b

  • 分配类型堆分配
  • 分配计数80957分配
  • 分配大小15,03 MB
  • 泄漏概率72%
函数mscorwks!CExecutionEngine::CheckThreadState+fe

  • 分配类型堆分配
  • 堆句柄0x00000000`00000000
  • 分配计数2个分配
  • 分配大小304字节
  • 泄漏概率98%
函数mscorwks!CLRMAPVIEWOFFILEX+4a

  • 分配类型虚拟内存分配
  • 分配计数4171分配
  • 分配大小为0字节
  • 泄漏概率73%
我想有人把我推向正确的方向我怎么能找到这个转储的内存泄漏?我能够将dump加载到windbg中并运行标准的windbg命令集,但我不知道哪一个是能够隔离泄漏的正确命令


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

使用弱引用可以减少内存使用。。这是非常普遍的,但一旦它为我节省了几乎几GB的内存,我最喜欢的调试.NET和Silverlight内存泄漏的方法就是使用SOS扩展。请参见此处,以快速浏览:

我通常做的是:

  • !!DumpHeap-stat获取内存中存在的对象的列表;这通常会指出问题的根源(例如,如果我看到一百万个微小的物体,它们只能使用一次,然后扔掉)
  • 一旦我知道是什么类型的对象导致了它,我就会使用!DumpHeap并随机获取其中一些(!GCRoot)的根。这通常会指示哪个对象意外地持有对泄漏对象的引用

  • 这假设您正在处理托管内存泄漏(引用被保存在您不希望的地方)。如果您处理的是非托管内存泄漏,则不会有多大帮助,但这种可能性要小得多,除非您的应用程序执行大量手动非托管内存管理(例如,P/Invoke的对象编组)。

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

    这里有一些可能有用的信息吗?你是否在使用任何COM对象作为你的代码的一部分,而你可能不会清理这些对象?乔:已经和其他20多人一起阅读了这篇文章,但仍然不知道在哪里以及如何找到漏洞。我有DebugDiag的详细日志,但当我不知道如何“阅读”它时,它就没用了:-我建议你避免关注非托管端,除非你的应用程序执行主要的非托管内存操作。在.NET应用程序中,我看到的内存问题的主要原因是到目前为止意外的引用—未删除事件处理程序是主要原因。更多信息请参见下面的答案。专用字节表示内存不与其他进程共享。托管堆不在进程之间共享,因此如果您有一个大的托管堆,私有字节将相应地增加。根据您的描述,我不清楚您是否在所有堆中看到一个大的私有字节数和一个小的#字节数。如果这两个数字都很大,那么您需要的是托管内存。我将尝试一下。你能把转储文件上传到某个地方并分享链接吗?我不太明白这对我有什么帮助?我已经完成了这个项目(由50+个.NET DLL组成)并且在某个地方有内存泄漏,所以我需要以某种方式隔离它..我的意思是。。。很有可能是GC没有收集一些已经使用SOS扩展的obj引用导致了泄漏,但我尝试的所有示例都不能帮助我隔离泄漏。正如我在帖子中所说,我使用了几乎所有的.NET man