【发布时间】:2011-05-24 03:48:33
【问题描述】:
我有一个循环变量,尽管已经超出范围,但似乎没有被垃圾收集(根据 Red--Gate ANTS 内存分析器)。
代码如下所示:
while (true)
{
var item = blockingQueue.dequeue(); // blocks until an item is added to blockingQueue
// do something with item
}
据我所知,在blockingQueue.dequeue() 返回之前,对item 的引用仍然存在。这是预期的行为,还是内存分析器中的错误?
其次,如果这是预期行为,我将如何强制 item 在循环体的末尾收集?将其设置为null 似乎不会导致它被收集。这很重要,因为队列可能会阻塞很长时间,并且item 引用了一个相当大的对象树。
注意,分析器的文档说,在拍摄内存快照之前执行 GC,并且引用不在终结器队列中。
我能够使用代码here 重现同样的问题。
更新
gist 中的代码略有缺陷,因为它合法地保留了 GetFoo() 中的引用。更改它后,对象确实现在在明确设置为null 时被收集。但是,我相信 Hans 的回答解释了我在实际代码中看到的情况。
【问题讨论】:
-
还有其他的参考吗?
-
你能显示item的所有用法吗?
-
分析器显示来自 GC 根的对象的引用,这就是其中之一。我在 github 上发布的示例显示了问题,并且 only 引用在循环内。
-
@Simon:我之前说过但删除了它,但是你用来重现这个的代码有问题。您使用 WinForms 应用程序中的控制台,更重要的是,您锁定并等待您的 UI 线程。问题是您的程序甚至不再运行,因为您正在等待一些不存在的线程来获取和释放锁。
-
您是否有理由关心该项目何时被 GCed?还要确保你是在发布模式而不是调试模式下编译,在调试中,局部变量的生命周期通常会延长,以使调试更容易。