为什么带有finalizer的类需要多个垃圾回收周期?

4
这篇文章指出:
如果一个对象有一个终结器(finalizer)方法,当垃圾回收器决定它不再“存活”时,它不会立即被移除。相反,它会成为一种特殊类型的根,直到.NET调用了终结器方法。这意味着这些对象通常需要多次垃圾回收才能从内存中删除,因为它们将在第一次被发现未使用时幸存下来。
那么我的问题是,为什么GC在发现对象不能被引用时不立即调用终结器并立刻收集该对象?为什么需要多次垃圾回收?
3个回答

5

需要考虑两个问题:

  • Finalizer 可能需要一些时间才能完成。例如,它可能会关闭一个资源或类似的操作。您不希望这成为垃圾收集时间的一部分,因为这可能会阻止线程执行工作(当它们只想获取一些内存时)。通过单独运行 finalization,GC 本身可以非常快速地完成,并且 finalization 工作可以与以后的其他工作并行进行。

  • Finalizer 可能通过使对象再次可见来复原该对象 - 但是检测到这种情况可能需要再次扫描内存…所以为什么不等到下一次发生呢?


2
因为(取决于所选的GC模式),当它执行GC时,它必须暂停运行时的关键部分。因此,您希望这个过程尽可能快。这会产生两个问题:
  1. 它不知道finalizer需要多长时间才能运行完毕(虽然有一个硬限制),并且不想延迟恢复运行时
  2. 运行时需要正常运行才能可靠地工作最终器(即使使用GC线程,您编写的代码也可能关心其他线程)
为了解决这两个问题,那些有待处理的finalizer被排队,然后在GC完成后(当运行时正在运行时)执行。
另外,结合IDisposable和finalizer是一个好习惯,并且让Dispose()取消finalization;这样它就不需要以后的finalization,并且可以在一步中清理。

0

当 .net 垃圾回收器运行时,对象被分为三类:从“正常”根引用可达的对象、不可由任何根引用访问的对象以及不可由任何“正常”根引用访问但已请求在其被放弃时接收通知的对象或者是从已请求通知的其他对象可达的对象。垃圾回收器会将第三类中的对象列入列表;该列表存储为根引用,使其中所有对象都处于“活动”状态。然而,系统会取消该列表中项目的“通知”请求,运行它们的 Finalize() 方法并将它们从列表中移除。如果在完成所有这些操作后,对象在任何地方都不存在引用,则该对象将在下一次 GC 循环中被声明为“死亡”。


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