2009-08-12 31 views
6

我有出现内存泄漏一个WindowsForms应用程序,所以我用展鹏的蚂蚁内存分析器来看看我怀疑的对象,发现他们是由物体在终结队列只开了。太好了,到底什么是Finalizer Queue?你能指出我的最佳定义吗?你能分享任何轶事建议吗?什么是Finalizer队列和Control + ThreadMethodEntry?

此外,Finalizer队列上的所有根GC对象都是实例System.Windows.Forms.Control + ThreadMethodEntry名为“caller”的对象。我发现它涉及到多线程的用户界面交互,但我除此之外不太了解。原谅我表面上的懒惰并承认无知,但这些资源全都埋在供应商的组成部分。我正在与供应商讨论这些问题,但我需要一些方向让我加快谈话速度。你能指出我对ThreadMethodEntry最有用的定义吗?任何轶事建议?

此外,我是否应该关心终结器队列上的这些对象?

更新:这对​​3210有帮助。

回答

14

终结器队列包含所有定义了终结器方法的对象。回想一下,终结器是一种收集非托管资源(如句柄)的方法。当垃圾收集器收集垃圾时,它将带有终结器的任何对象移动到终结器队列中。在稍后的某个时刻 - 根据内存压力,GC启发式和月球的相位 - 当垃圾收集器决定收集这些对象时,它沿着队列走下来并运行终结器。

已经在过去的内存泄漏的工作,看到一大堆供应商的对象终结队列可能是草率的代码,但它并不表示内存泄漏。通常,良好的代码将公开一个Dispose方法,该方法将收集托管资源和非托管资源,并通过GC.SuppressFinalize()将其自身从终结器队列中移除。因此,如果供应商的对象确实实现了Dispose方法,并且您的代码没有调用它,那么这可能会导致终结器队列中的一堆对象。

您是否尝试过在时间上创造了两个点之间的蚂蚁快照,并比较它们之间创建的对象?这可以帮助您识别任何被泄露的管理对象。

另外,如果你想看看记忆消失时终结器运行,试试这个只是测试:

 
System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); // this method may block while it runs the finalizers 
System.GC.Collect(); 

我不建议正常运行这段代码。如果你刚刚完成了大量工作并创建了大量垃圾,则可能需要运行它。例如,在我们的应用程序中,我们的一个函数可以创建大约350 MB的垃圾,在关闭MDI窗口后浪费掉。由于这已知会留下大量垃圾,我们手动强制垃圾收集。

另请注意,在基本Windows.Forms代码中有一个低级属性缓存,它将保留在上次打开的模式对话框中。这可能是内存泄漏的根源。摆脱这种引用的一个可靠方法是强制出现另一个简单的对话框,然后运行上面的GC代码。

+0

谢谢你的出色答案,保罗。这是我正在谈论的对象引用图,在清理资源之后查看第二个快照中的新对象。图中实现IDisposable的所有对象都有一个工具提示,说“已为此对象调用Dispose()”,但所选对象没有此工具提示。 – flipdoubt 2009-08-12 21:24:54

+2

关于ThreadMethodEntry的注意事项:我认为它们用于UI线程的任何调用。每个Control对象都有一个ThreadMethodEntry类型的线程回调队列。一个回调出队一个ThreadMethodEntry并运行它。 每个ThreadMethodEntry对象都有一堆内部字段。检查这些字段可能会帮助您找出哪些供应商的对象正在调用。我不记得是否可以从ANTS获取这些信息,但我知道你可以通过WinDbg.dll和sos.dll(托管调试器扩展)。看看“方法”委托和“调用者”控件。 – 2009-08-12 22:04:41

+0

另请注意,ThreadMethodEntry对象实现了一个终结器,但它们没有Dispose方法。当他们完成时,他们也会被移动到终结者队列中。 – 2009-08-12 22:05:17

1

终结队列一种情况,即不再使用的对象实例等待由GC定稿的队列。此队列中的所有对象都将被最终确定,并且您的内存泄漏可能不会直接来自其中一个对象。但是,其中一个对象可能不会释放其所有非托管资源。

ThreadMethodEntry类是IAsyncResult的实现,此类的实例通常在调用异步操作时创建,例如使用Invoke更新UI或使用Begin */End *方法。

0

Here's一个很好的博客文章,其中描述了类似的问题。在技​​术层面上,您可以使用SOS.dll(博客文章描述)和Sosex.dll来帮助您找出为什么这些ThreadMethodEntry对象在内存中闲置。这些WinDbg扩展中有一些命令可以跟踪其他对象在内存中引用特定对象的内容。