如果垃圾收集器在同一代码中两次保留内存,是否可以调用两次 finalize() 方法?

Can the finalize() method be called twice if the garbage collector retains memory twice in the same code?

我在很多地方都发现,java中的finalize()方法是在垃圾收集器或System.gc()成功保留了冗余对象消耗的内存而不再需要时调用的对它的引用。还发现这个方法被调用的次数不超过一次。我对 java 并不陌生,但也不是很有经验。可能我理解有误 但是先说一段代码

public class Solution {
    @Override
    protected void finalize(){
        System.out.print("method called");
    }
    public static void main(String... args){
        Solution obj1= new Solution();
        Solution obj2 = new Solution();
        Solution obj3 = new Solution();
        System.gc();
        obj1=obj2;
        System.gc();
        obj3=null;
        System.gc();
    }
}

这里,finalize方法被调用了两次,因为内存堆有两次符合垃圾清理的条件。所以,我有点困惑我是否知道整个事情是正确的,或者它是否应该按照它的行为方式行事。

没有。 finalize() 方法只会被对象的 GC 调用一次。 JVM 在对象头(我认为)中设置了一个标志,表示它已经完成,并且不会再次完成。

javadoc 明确指出:

" The finalize method is never invoked more than once by a Java virtual machine for any given object. "

当然,没有什么可以阻止对象方法多次调用 this.finalize()


请注意,finalize() 在 Java 9 及更高版本中 已弃用 ,原因在 javadoc 中已说明。建议您改为使用以下其中一项:

  • AutoCloseable + 尝试使用资源
  • Cleaner
  • PhantomReference

有人这样评价:

finalize() is called for every Object that is collected.

由于几个原因,这不是真的。

  • javadoc 明确 声明不保证 finalize 会被调用。可以保证的是,在对象的存储被回收之前,它会被调用(一次)。这比评论中的陈述更弱。

    如果 JVM 在 GC 运行.

    后很快退出,则可能无法最终确定垃圾收集对象的一种情况。

    当 classes finalize 方法从不 returns1 时,会出现另一种(病态)情况。当 class 的一个实例被终结时,终结器线程将被卡住。当所有终结器线程都以这种方式卡住时,将无法终结更多可终结对象2.

  • 如果 Object::finalize 未在 class 中被覆盖,JVM 将跳过 class.

    的最终化步骤

1 - 这可能是由于无限循环,或者是因为 finalize() 方法卡在等待锁定或等待从未发生的内部或外部“事件”。另请注意,在这种情况下,“从不”可能意味着“不会很长时间”。整体效果可以一样。
2 - 对象将无限期地位于终结队列中。这是内存泄漏。