0

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

我已经阅读了哪些策略和工具对在 .NET 中查找内存泄漏有用?,我知道有一些工具和/或框架可以处理这个“大图”,我相信几周后我会尝试其中的几种方法。现在我只是有一种非常强烈的感觉,我可能有与未删除的表单有关的泄漏,所以只想检查这件事(我想知道只是为了知道)。

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

4

2 回答 2

3

这里确实有两个问题:

至于您最初的问题,您可以使用 Wea​​kReference 来监视对象的存在而不影响其生命周期。

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

于 2012-05-10T05:10:11.037 回答
0

托管语言的整个概念是,您不需要关心对象何时实际被垃圾回收。大量的时间和精力投入到 GC 中,以确保它不会收集不应该收集的对象,不会留下它应该收集的对象(当它决定通过它在)并且所有这些都合理有效地完成。这意味着,如果一个对象消耗大量托管资源并且还实现了 IDisposable(例如,DataTable 或 DataSet)被释放,它仍然会消耗一定的内存,并且释放它不会使其更快地被垃圾收集(尽管您仍然应该处理它以确保任何托管资源消失)。

当您不理会它并让它完成它的工作而不是通过尝试(例如,手动导致收集发生)来干扰它时,GC 的构建效果最好。这有时对调试目的或了解您的程序/语言很有用,但它实际上从不属于生产应用程序。

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

现在,考虑到所有这些,程序仍然有可能发生内存泄漏,但是您确实需要先问自己几个问题。泄漏量有多大?每次我们执行函数 X 等时,它是一次性的、连续的吗?程序消耗如此多的内存会造成破坏(内存不足,导致其他程序内存不足等),这可能会发生在程序的常见或合法使用中吗?通常你不需要开始问这些类型的问题,直到你开始出现内存不足异常,或者注意到你开始用完一个不应该出现的程序的物理内存。如果您注意到这些问题,那么您可以开始四处寻找实现 IDisposable 且未被处置的对象,看看您是否“

对不起,文字墙。

于 2012-05-10T05:26:39.643 回答