.net应用程序内存泄漏+奇怪的GC行为



我不太确定该去哪里寻求帮助,所以我想我应该试试stackoverflow,因为它通常能回答我90%的编程相关问题。

简而言之,我有一个开源的。net应用程序内存泄漏。从某种意义上说,它可能不是真正的内存泄漏,当应用程序关闭时,我怀疑内存被回收了,但是当它运行时,它不断分配更多的内存而不释放它。最后,抛出一个System.OutOfMemoryException

为了调试问题,我遵循了本文中建议的步骤,并生成了以下图表,其中红色是. net/clr内存"所有堆中的#字节",绿色是使用windows的性能监视器工具的进程"私有字节"(注意,绿线已被均匀地缩小,以显示更接近红线,因为只有线条的形状对我很重要):性能监视器输出。

我将该图像作为托管内存泄漏的证据,然后使用windows的"调试诊断工具"尝试找到泄漏的来源(如本文中提到的)。但是,我从调试诊断工具得到的报告非常奇怪。

基本上每次尝试收集"完整UserDump",我试图在应用程序运行时每5秒做一次,被垃圾收集器总是在垃圾收集周期中间的事实所挫败,导致调试诊断工具输出错误,并阻止它收集任何有用的。net内存相关信息。

现在我卡住了,我知道我有一个托管内存泄漏,但我不知道如何缩小它在哪里。我还对垃圾收集器如何总是处于收集周期的中间感到困惑,这让我怀疑垃圾收集线程是否以某种方式阻塞,阻止它释放内存和/或退出垃圾收集周期。

在性能监控图的某些部分,分配的。net内存下降了一点,所以垃圾收集器不会永远卡住,但它必须在大多数时间,否则调试诊断应该已经能够做一个UserDump。

几个问题:

  1. 是否有可能在。net应用程序中的垃圾收集器在试图释放一些内存时卡住,也许是从一些编码不良的析构函数/终结器或其他东西?

  2. 我可以使用什么策略来继续缩小问题的根源?

如果您提供将会有所帮助。. NET框架版本,操作系统版本,进程的比特数和机器上的处理器数量。如果你很快得到内存不足异常,它会让我认为你正在运行一个32位进程,但如果你能确认,仍然会有所帮助。

首先,您应该通过查找进程的GC内存计数器中的%Time来检查GC是否确实是问题的原因。您可以在. net CLR内存对象下的PERFMON中监控这一点。如果这个计数器> 30%,那么肯定有GC问题。你粘贴的PNG并没有告诉我每秒分配了多少内存,所以如果它很高,那么GC将会启动更多。

需要注意的是,使用最新的调试诊断工具来分析转储,看看是否发现了不同的东西。在DebugDiag 1.2中有一个问题,它可能导致错误地报告"垃圾收集的中间"消息,因此您希望确保在转储时GC是否真的在运行。您可以从http://www.microsoft.com/en-us/download/details.aspx?id=40336下载最新版本,并使用该工具分析相同的转储文件,看看它是否报告了不同的内容。还要在报告中搜索GarbageCollectionGeneration字符串,这将显示负责调用GC的线程。查看该线程的堆栈,您可能能够确定该线程正在做什么,最终调用了GC。这可能有帮助,也可能没有。

回答你的其他问题:-

1)如果任何线程禁用了抢占式GC,则GC可能会卡住。您可以阅读文章http://blogs.msdn.com/b/tess/archive/2008/02/11/hang-caused-by-gc-xml-deadlock.aspx了解更多关于抢占式GC以及如何找出禁用了抢占式GC的线程。

2)我会在WinDBG中打开转储文件,然后按照上面博客中提到的方法看看我是否达到了某个地方。如果框架是。net framework 4.0或更高版本,您还可以使用PERFVIEW工具来收集跟踪,这将提供有关GC发生原因的良好信息。查看PERFVIEW的视频,以解决GC问题http://channel9.msdn.com/Series/PerfView-Tutorial/PerfView-Tutorial-9-NET-Memory-Investigation-Basics-of-GC-Heap-Snapshots

如果这个EXE正在做一些后台处理,你可能想要启用GC的服务器模式,看看这是否有帮助。阅读文章http://blogs.msdn.com/b/clyon/archive/2004/09/08/226981.aspx获取更多信息。

希望这有帮助!!

最新更新