什么是终结器队列和 Control+ThreadMethodEntry? [英] What are the Finalizer Queue and Control+ThreadMethodEntry?

查看:22
本文介绍了什么是终结器队列和 Control+ThreadMethodEntry?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

更新:这个 红门文章很有帮助.

解决方案

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

过去曾处理过内存泄漏问题,在终结器队列中看到一堆供应商的对象可能是草率的代码,但这并不表示内存泄漏.通常,好的代码会公开一个 Dispose 方法,该方法将收集托管和非托管资源,并在此过程中通过 GC.SuppressFinalize() 从终结器队列中删除自己.因此,如果供应商的对象确实实现了 Dispose 方法,而您的代码没有调用它,则可能会导致终结器队列中出现一堆对象.

您是否尝试过在 ANTS 中在两个时间点之间创建快照并比较它们之间创建的对象?这可以帮助您识别任何被泄露的托管对象.

此外,如果您想查看运行终结器时内存是否消失,请尝试使用以下方法进行测试:

<前>System.GC.Collect();System.GC.WaitForPendingFinalizers();//此方法在运行终结器时可能会阻塞System.GC.Collect();

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

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

I have a WindowsForms app that appears to leak memory, so I used Redgate's ANTS Memory Profiler to look at the objects I suspect and find that they are only held by objects already on the Finalizer Queue. Great, exactly what is a the Finalizer Queue? Can you point me to the best definition? Can you share any anecdotal advice?

Also, all the root GC objects on the Finalizer Queue are instances of System.Windows.Forms.Control+ThreadMethodEntry objects named "caller". I see that it is involved in multi-thread UI interaction, but I do not know much beyond that. Forgive my apparent laziness and admitted ignorance, but these resources are all buried within a vendor's component. I am talking to the vendor about these issues, but I need some direction to get me up to speed on the conversation. Can you point me to the most useful definition of ThreadMethodEntry too? Any anecdotal advice?

Also, should I even be concerned about these objects on the finalizer queue?

Update: This Red Gate article was helpful.

解决方案

The finalizer queue holds all objects that have a finalizer method defined. Recall that a finalizer is a means to collect unmanaged resources like handles. When the garbage collector collects garbage, it moves any objects with a finalizer into the finalizer queue. At some point later-- depending on memory pressure, GC heuristics, and the phase of the moon-- when the garbage collector decides to collect these objects, it walks down the queue and runs the finalizers.

Having worked with memory leaks in the past, seeing a bunch your vendor's objects in the finalizer queue could be sloppy code, but it does not indicate a memory leak. Typically, good code will expose a Dispose method that will collect both managed and unmanaged resources, and in doing so, remove themselves from the finalizer queue via GC.SuppressFinalize(). So, if the vendor's objects do implement a Dispose method, and your code doesn't call it, that could lead to a bunch of objects in the finalizer queue.

Have you tried creating a snapshot in ANTS between two points in time and comparing the objects created between them? That may help you identify any managed objects being leaked.

Also, if you want to see if the memory goes away when the finalizers are run, try this just to test with:

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

I do not recommend running this code normally. You might want to run it if you've just done a ton of work and created lots of garbage. For example, in our app, one of our functions can create about 350 MB of garbage that goes to waste after closing an MDI window. Since this is known to leave lots of garbage, we manually force garbage collection.

Also note that there is a low-level property cache in the base Windows.Forms code that will hold on to the last opened modal dialog. This could be a source of a memory leak. One sure way to get rid of this reference is to force another simple dialog to appear, then run the above GC code.

这篇关于什么是终结器队列和 Control+ThreadMethodEntry?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆