我有一个 WindowsForms 应用程序似乎会泄漏内存,因此我使用 Redgate 的 ANTS Memory Profiler 来查看我怀疑的对象,发现它们仅由已存在于 终结器队列. 。太好了,到底什么是终结器队列?你能给我指出最好的定义吗?您能分享一些轶事建议吗?

此外,Finalizer Queue 上的所有根 GC 对象都是 System.Windows.Forms.Control+ThreadMethodEntry 名为“调用者”的对象。我看到它涉及多线程UI交互,但除此之外我不知道太多。请原谅我明显的懒惰和承认的无知,但这些资源都隐藏在供应商的组件中。我正在与供应商讨论这些问题,但我需要一些指导来加快对话速度。您能给我指出 ThreadMethodEntry 最有用的定义吗?有什么轶事建议吗?

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

更新:红门文章 很有帮助。

有帮助吗?

解决方案

在终结队列保存已定义一个终结方法的所有对象。回想一下,一个终结是收集非托管资源的手柄一样的手段。当垃圾收集器收集的垃圾,它移动的任何对象与一个终结到终结队列。在一些点later--取决于存储器的压力,GC试探法,并且当所述垃圾收集器决定收集这些对象的moon--的相位,它走下队列并运行终结。

已经在过去的内存泄漏的工作,看到一大堆供应商的对象终结队列可能是草率的代码,但它并不表示内存泄漏。通常情况下,良好的代码将暴露将收集托管和非托管资源的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

其他提示

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

在ThreadMethodEntry类是调用异步操作的情况下,像使用调用来更新用户界面或使用开始* /结束*方法通常创建的IAsyncResult和这个类的实例的实现方式。

这是 一篇很好的博客文章描述了类似的问题。在更技术的层面上,您可以考虑使用 SOS.dll(博客文章中对此进行了描述)和 dll文件 帮助您弄清楚为什么这些 ThreadMethodEntry 对象挂在内存中。这些 WinDbg 扩展中的命令可以跟踪哪些其他对象正在引用内存中的特定对象。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top