我在很多地方发现,当垃圾收集器或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 - 对象将无限期地位于完成队列中。 这是内存泄漏。