如何知道winform表单是否已被垃圾收集?

时间:2012-05-10 04:36:59

标签: c# .net winforms garbage-collection

我正在使用C#,但在VB.NET中可能是相同的。 I C ++我只想在对象析构函数上设置一个断点,以了解它何时/是否被删除/释放。据我所知,在winforms中,基类调用SupressFinalize,因此永远不会调用表单析构函数,所以我想我不能这样做。 是否有另一种方法可以知道某个对象是否已被垃圾收集?这似乎是一个catch-22,因为如果有,你可能需要一个引用来检查,但是通过持有该引用,收集的垃圾将不要粉碎它。

我已经阅读了这个What strategies and tools are useful for finding memory leaks in .NET?,我知道有一些工具和/或框架来处理这个“大局”,我相信几周后我会尝试几个这些方法。现在我只是有一种非常强烈的感觉,我可能有一个与表格没有删除有关的泄漏,所以只想检查这一件事(我想知道只是为了知道)。

我知道我可以观看Dispose,但我很确定Dispose可以被调用,但最终还是表单对象仍然存在。为了测试这个理论,我创建了一个已知问题,我在表单中注册了一个回调事件,然后关闭表单而不注销它。果然,Dispose被调用(并且“disposing”是真的),但是稍后当事件被触发时,它仍然在我认为已经被处置的形式内的我的断点处。

2 个答案:

答案 0 :(得分:3)

这里确实存在两个问题:

至于您的原始问题,您可以使用WeakReference来监控对象的存在,而不会影响其生命周期。

您的基本问题表明您对垃圾收集是什么以及它是如何工作存在误解。垃圾收集的关键是你永远不应该关心是否收集了一个对象。相反,您应该专注于对象的引用,以及它们是否已被重新分配或从根目录引用中无法访问。不要担心实例,担心引用它。

答案 1 :(得分:0)

托管语言的整个概念是,您不需要关心对象实际上是否被垃圾回收。 GC需要花费大量的时间和精力来确保它不会收集它不应该收集的对象,它不会留下它应该收集的对象(当它决定对这一代进行传递时它在所有这些都是合理有效地完成的。这意味着如果一个对象消耗了大量的托管资源并且还实现了IDisposable(比如,一个DataTable或DataSet),那么它仍然会占用一块内存,并且处理它并不会让它更快地被垃圾收集。 (尽管您仍应处置它以确保任何托管资源消失)。

GC的构建是为了让您在不管它的情况下工作得最好,并让它完成工作,而不是通过尝试手动导致收集来干扰它。这有时用于调试目的或了解您的程序/语言,但它实际上从未属于生产应用程序。

处置与垃圾收集或收集对象无关。 Disposing是用于处理托管对象的机制,该托管对象保留在未处理的资源(或另一个保留在未处理资源上的对象)上。处置对象告诉它清除非托管资源,但它与垃圾收集器无关,释放该对象的托管资源。析构函数就在那里,因此在释放非托管资源之前不会释放托管资源,但在释放托管资源之前,非托管资源(通过dispose)可以完全接受(实际上应该总是这样)。

现在,鉴于所有这些,一个程序有内存泄漏仍然是可能的,但是有一些问题你真的需要首先问自己。泄漏有多大?它是一次性的,随着时间的推移,每次我们做X功能等?程序消耗如此多的内存以致于破坏性(内存耗尽,导致其他程序内存耗尽等)并且可能在程序的常见或合法使用中发生,需要什么?通常,在开始出现内存异常之前,您不需要开始询问这些类型的问题,或者注意到您开始耗尽物理内存以用于不应该执行的程序。如果您发现这些问题,那么您可以开始寻找实现IDisposable的未被处理的对象,以查看您是否持有对不再需要的非常大的对象(或对象集合)的引用,等等。

对不起文字墙。