在垃圾回收期间,是否会调用所有的终结器?

4
假设我想分配100个字节,但由于在我的GC堆中没有100个可用的字节,因此会触发垃圾回收。此外,在我的GC堆中有价值100mb的不可访问对象。据我了解,一旦GC释放了100个字节,它可以决定停止收集并继续程序的执行。所以假设GC没有释放50mb的对象,这相当于100个不同的对象。
我的问题是:GC是否调用所有的终结器?即使它不打算删除它们?(在这种情况下,GC决定不删除的100个不可访问对象)。
5个回答

14

问题在于这里的任何东西都可能是实现细节,并且在x86 / x64 / ia64、服务器与工作站(GC配置非常不同)、Mono vs MS .NET、操作系统版本、.NET/CLI主要版本、.NET/CLI补丁版本、紧凑框架、微框架等方面可能有所不同。

我认为你不应该假设任何特定行为,除了“具有终结器但未使用的对象可能会在某个时候被终结”,但即使这也不能保证。


1
+1。换句话说,“你不需要知道,也不应该过多思考”。 - Adam Robinson
不能说出来的,就必须保持沉默。 - mlo

1
"

一旦GC释放了100字节,它可以决定停止回收

"- 不,GC不会停止回收。它将始终回收第0代对象。如果这还不足够,就会继续回收第1代和第2代+LOB的对象。


1
在.NET中,垃圾回收有两个方面:终结和销毁。当创建一个具有终结器的对象时,它会被添加到一个特殊的列表中,我称之为“可终结”列表。每次垃圾回收运行时,它会识别出那些不可达的对象,那些仅从“可终结”列表或其中的对象可达的对象,以及那些通过其他方式可达而无需经过“可终结”列表的对象。完全不可达的对象将被销毁。仅从“可终结”列表或其中的对象可达的对象将从该列表中移除,并放入“立即终结”列表中。可通过其他方式而非“可终结”列表可达的对象将幸存于GC中。在GC将对象分类为这三类时,所有代码执行都会停止。一旦GC完成,代码执行将恢复,并且一个特殊的线程将开始运行“立即终结”列表中所有对象的Finalize方法。
请注意,“立即终结”列表中的对象以及由此引用的任何对象只要在该列表中,就不会被垃圾回收;只有在它们的终结器运行后才能成为垃圾回收的候选对象。一旦它们不再在“立即终结”列表中,它们可能再次成为可回收对象。

0

答案是否定的。只有在对象被销毁时,才会运行终结器。


“即使[对象]未被垃圾回收,finalizers是否会被调用?” - 明显的答案是不会。 - Alex
符合终结条件的对象因为这个原因不符合销毁条件。一旦一个对象被终结,它将不再符合终结条件;因此,除非在终结过程中(自己或其他对象的终结)创建了对它的强引用,否则它将符合销毁条件。 - supercat

0
GC 进行多次遍历。它寻找不可达对象,并在找到它们时检查它们是否有 finalizer。如果有 finalizer,则将它们放入单独的 finalizer 队列中;如果没有,则清理它们。因此,在第一次遍历中,它实际上不会调用任何 finalizer,只是根据对象是否具有 finalizer 来组织它们。

你没有理解我的答案重点... 问题是垃圾回收器是否可以在不需要释放任何对象时决定停止回收(因此即使发生了“某些集合”,它们的终结器也不会被调用)。 - unknown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接