Finalizer Queue 和 Control+ThreadMethodEntry 是什么?
我有一个 WindowsForms 应用程序似乎存在内存泄漏,因此我使用 Redgate 的 ANTS Memory Profiler 来查看我怀疑的对象,发现它们仅由 Finalizer Queue 上已有的对象所持有。 太好了,到底什么是终结器队列? 你能给我指出最好的定义吗? 您能分享一些轶事建议吗?
此外,Finalizer 队列上的所有根 GC 对象都是名为“caller”的 System.Windows.Forms.Control+ThreadMethodEntry 对象的实例。 我看到它涉及多线程UI交互,但除此之外我不知道太多。 请原谅我明显的懒惰和承认的无知,但这些资源都隐藏在供应商的组件中。 我正在与供应商讨论这些问题,但我需要一些指导来加快对话速度。 您能给我指出 ThreadMethodEntry 最有用的定义吗? 有什么轶事建议吗?
另外,我是否应该关心终结器队列中的这些对象?
更新:此红门文章很有帮助。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
终结器队列保存定义了终结器方法的所有对象。 回想一下,终结器是一种收集非托管资源(例如句柄)的方法。 当垃圾收集器收集垃圾时,它将带有终结器的所有对象移动到终结器队列中。 在稍后的某个时刻(取决于内存压力、GC 启发式和月相),当垃圾收集器决定收集这些对象时,它会沿着队列走下去并运行终结器。
过去处理过内存泄漏问题,在终结器队列中看到一堆供应商的对象可能是草率的代码,但这并不表示存在内存泄漏。 通常,好的代码会公开一个 Dispose 方法,该方法将收集托管和非托管资源,并通过 GC.SuppressFinalize() 将其自身从终结器队列中删除。 因此,如果供应商的对象确实实现了 Dispose 方法,而您的代码没有调用它,则可能会导致终结器队列中出现一堆对象。
您是否尝试过在 ANTS 中创建两个时间点之间的快照并比较它们之间创建的对象? 这可以帮助您识别任何正在泄漏的托管对象。
另外,如果您想查看运行终结器时内存是否消失,请尝试以下测试:
我不建议正常运行此代码。 如果您刚刚完成了大量工作并产生了大量垃圾,您可能想要运行它。 例如,在我们的应用程序中,我们的函数之一可能会创建大约 350 MB 的垃圾,这些垃圾在关闭 MDI 窗口后就会被浪费掉。 由于已知这会留下大量垃圾,因此我们手动强制垃圾收集。
另请注意,基本 Windows.Forms 代码中有一个低级属性缓存,它将保留最后打开的模式对话框。 这可能是内存泄漏的根源。 摆脱此引用的一种可靠方法是强制显示另一个简单的对话框,然后运行上面的 GC 代码。
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:
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.
终结器队列是不再使用的对象实例等待 GC 终结的队列。 该队列中的所有对象都将被最终确定,并且您的内存泄漏可能不是直接来自其中之一。 但是,这些对象之一可能不会释放其所有非托管资源。
ThreadMethodEntry 类是 IAsyncResult 的实现,该类的实例通常在调用异步操作时创建,例如使用 Invoke 更新 UI 或使用 Begin*/End* 方法。
The finalizer queue is a queue where the object instances that are not used anymore are waiting to be finalized by the GC. All objects in this queue will be finalized and your memory leaks does probably not come from one of these ones directly. But, one of these objects may not release all its unmanaged resources.
The ThreadMethodEntry class is an implementations of IAsyncResult and instances of this class are typically created when invoking asynchronous operations, like using Invoke to update the UI or using Begin*/End* methods.
这里一篇很好的博客文章描述了类似的问题。 在更技术的层面上,您可以考虑使用 SOS.dll (博客文章中对此进行了描述)和 Sosex.dll 来帮助您找出这些 ThreadMethodEntry 对象在内存中徘徊的原因。 这些 WinDbg 扩展中的命令可以跟踪哪些其他对象正在引用内存中的特定对象。
Here's a good blog post which describes a similar issue. At a more technical level, you could look to using SOS.dll (which the blog post describes) and Sosex.dll to help you work out why these ThreadMethodEntry objects are hanging around in memory. There are commands in these WinDbg extensions that can track down what other objects are referencing a specific object in memory.