java - finalizable 对象如何至少需要 2 个垃圾收集周期才能被回收?

标签 java garbage-collection finalize

我正在阅读 this这篇文章,我真的无法理解可终结对象(覆盖finalize 方法的对象)如何在回收之前至少需要 2 个 GC 周期

It takes at least two garbage collection cycles (in the best case) before a finalizeable object can be reclaimed.

谁也能详细解释一下一个finalizable对象怎么可能需要一个以上的GC周期来回收?

我的逻辑论点是,当我们覆盖 finalize 方法时,运行时将不得不向垃圾收集器注册这个对象(这样 GC 就可以调用这个对象的 finalize,这让我认为GC 将引用所有可终结的对象)。为此,GC 必须保持对可终结对象的强引用。如果是这样,那么这个对象最初是如何成为 GC 回收的候选对象的呢?我通过这个理论得出了一个矛盾。

PS:我知道重写 finalize 不是推荐的方法,并且自 Java 9 以来不推荐使用此方法。

最佳答案

你是对的,因为垃圾收集器需要对可终结对象的引用。当然,在确定对象在终结之前是否仍然可达时,一定不要考虑这个特定的引用。这意味着对垃圾收集器引用的性质有特殊的了解。

当垃圾收集器确定一个对象有资格进行终结时,终结器将运行,这意味着该对象再次变得强可达,至少只要执行终结器。完成后,对象必须再次变得不可访问,并且必须检测到这一点,然后才能回收对象的内存。这就是为什么它至少需要两个垃圾收集周期。

对于广泛使用的 Hotspot/OpenJDK 环境(也可能在 IBM 的 JVM 中),这是通过创建 Reference 的特殊非公共(public)子类的实例来实现的。 , 一个 Finalizer ,就在创建一个对象时,该对象的类具有非平凡的 finalize() 方法。与弱引用和软引用一样,当不存在对引用对象的强引用时,这些引用会被垃圾收集器排入队列,但它们不会被清除,因此终结器线程可以读取对象,使其再次强可达以进行终结。此时,Finalizer 被清除,但也不再被引用,所以无论如何它都会像普通对象一样被收集,所以下次引用对象变得不可访问时,不再存在对它的特殊引用.

对于其类具有“普通终结器”的对象,即 java.lang.Object 继承的 finalize() 方法或空的 finalize() 方法,JVM 会走捷径,不会首先创建 Finalizer 实例,所以你可以说,构成所有对象大部分的这些对象的行为如下如果他们的终结器确实已经运行,则从一开始就运行。

关于java - finalizable 对象如何至少需要 2 个垃圾收集周期才能被回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53791900/

相关文章:

java - Wildfly 10.1.0.FINAL 上的内存泄漏 (java.lang.ref.Finalizer/ActiveMQConnection)

java - 如何在java中销毁一个对象?

java - 加载到内存中的文件比磁盘上的文件大

python - 在 Python 中 : How to remove an object from a list if it is only referenced in that list?

java - 在 setter/getter 中创建新对象,确保它不位于虚拟机中

c# - 解决C#内存泄漏的方法有哪些

c# - Windows Phone,即使只有弱引用,垃圾收集器也不会清理 View

java - 使用Java划分时间

java - 线程安全 InetAddress.isReachable()

java - 如何在JPQL中随机选择10条记录?