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



我在很多地方发现,当垃圾收集器或System.gc((成功保留冗余对象消耗的内存而不再引用它时,Java中的finalize((方法会被调用。还发现这种方法调用次数不超过一次。我对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();
}
}

在这里,最终方法被调用两次,因为内存堆有资格进行两次垃圾清理。所以,我有点困惑我是否对整个事情了如指掌,或者它是否应该按照它的行为方式行事。

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

javadoc 明确指出了这一点:

" Java虚拟机对任何给定对象调用的finalize方法永远不会超过一次。

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


请注意,由于 javadoc 中所述的原因,finalize()在 Java 9 及更高版本中已被弃用。 建议您改用下列方法之一:

  • AutoCloseable+ 试用资源
  • Cleaner
  • PhantomReference

有人这样评论:

收集的每个Object都会调用finalize()

由于几个原因,情况并非如此。

  • javadoc明确指出,不能保证finalize会被调用。 可以保证的是,在回收对象的存储之前,它将被调用(一次(。 这种说法比评论的说法要弱。

    垃圾回收对象可能无法完成的一种情况是 JVM 在 GC 运行后不久退出。

    当类finalize方法从不返回1时,会发生另一种(病理(情况。 当该类的实例完成时,终结器线程将卡住。 当所有终结器线程都以这种方式卡住时,无法再完成可终结的对象2.

  • 如果类中的Object::finalize未被覆盖,那么 JVM 将跳过该类的完成步骤。


1 - 这可能是由于无限循环,或者因为finalize()方法卡在等待锁或等待从未发生的内部或外部"事件"中。 另请注意,在这种情况下,"从不"可能意味着"很长一段时间不"。 总体影响可能是相同的。
2 - 对象将无限期地位于完成队列中。 这是内存泄漏。

相关内容

  • 没有找到相关文章

最新更新