我有一个似乎泄漏内存的WindowsForms应用程序,因此我使用Redgate的ANTS Memory Profiler查看我怀疑的对象,发现它们仅由 Finalizer Queue 中已经存在的对象保存。太好了,终结器队列到底是什么?您能指出我的最佳定义吗?您可以分享任何轶事建议吗?
另外,终结器队列上的所有根GC对象都是 System.Windows.Forms.Control + ThreadMethodEntry 对象的实例,这些对象名为“调用方”。我看到它参与了多线程UI交互,但是我对此并不了解。原谅我表面上的懒惰和公认的无知,但是这些资源全都埋在供应商的组件中。我正在与供应商讨论这些问题,但是我需要一些指导以使我加快对话的速度。您还能指出我最有用的ThreadMethodEntry定义吗?有什么轶事建议吗?
另外,我是否应该担心终结器队列上的这些对象?
更新:此Red Gate article很有帮助。
最佳答案
终结器队列包含已定义终结器方法的所有对象。回想一下,终结器是一种收集诸如句柄之类的非托管资源的方法。垃圾收集器收集垃圾时,会将带有终结器的所有对象移动到终结器队列中。稍后在某个时候(取决于内存压力,GC启发法和月相),当垃圾收集器决定收集这些对象时,它将沿着队列走,并运行终结器。
过去处理过内存泄漏,在终结器队列中看到一堆供应商的对象可能是草率的代码,但这并不表示内存泄漏。通常,好的代码会公开一个Dispose方法,该方法将同时收集托管资源和非托管资源,并通过GC.SuppressFinalize()
将自己从终结器队列中删除。因此,如果供应商的对象确实实现了Dispose方法,而您的代码未调用它,则可能导致终结器队列中有许多对象。
您是否尝试过在两个时间点之间在ANTS中创建快照,并比较两个时间点之间创建的对象?这可以帮助您识别所有泄漏的托管对象。
另外,如果要查看运行终结器时内存是否消失,请尝试执行此操作以进行以下测试:
System.GC.Collect();
System.GC.WaitForPendingFinalizers();//此方法在运行终结器时可能会阻塞
System.GC.Collect();
我不建议正常运行此代码。如果您刚刚完成了大量工作并创建了很多垃圾,则可能要运行它。例如,在我们的应用程序中,我们的功能之一可以创建约350 MB的垃圾,这些垃圾在关闭MDI窗口后就浪费掉了。由于已知会留下大量垃圾,因此我们手动强制垃圾收集。
另请注意,基本Windows.Forms代码中有一个低级属性缓存,将保留到最后打开的模式对话框中。这可能是内存泄漏的根源。摆脱该引用的一种可靠方法是强制另一个简单对话框出现,然后运行上面的GC代码。
关于.net - 什么是终结器队列和Control + ThreadMethodEntry?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1268525/