正如您在进入if分支之前在第一个区块SAVE_HOOK = null;
中看到的那样,我认为SAVE_HOOK == null
,所以它不应该进入SAVE_HOOK.isAlive();
。但实际上,我在Eclipse
:
Eclipse IDE for Java Developers
版本:Neon.3发布(4.6.3)
构建ID:20170314-1500
为什么会这样?
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println("yes, i am still alive :)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize mehtod executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws Throwable {
SAVE_HOOK = new FinalizeEscapeGC();
// ---------------block 1----------------//
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK != null) { // "SAVE_HOOK = null;"
SAVE_HOOK.isAlive(); // why the frist time it can go inside this if branch?
} else {
System.out.println("no, i am dead :(");
}
// ---------------block 1----------------//
// the same as the above block
// ---------------block 2----------------//
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no, i am dead :(");
}
// ---------------block 2----------------//
}
}
结果:
敲定mehtod执行!
是的,我还活着。) 不,我死了:(答案 0 :(得分:1)
归结为:对象只能在其生命周期内完成一次。 finalize方法可以使对象第一次转义删除,但下次对象被检测为无法访问,它将被删除。
答案 1 :(得分:1)
听起来你正试图提出两个问题:
SAVE_HOOK
在第一个阻止后不为空?第一个问题的简单答案是:因为System.gc()
触发了垃圾收集器,垃圾收集器又运行了终结器,它明确地重新分配了引用。但我猜你已经知道了,你的意思是:为什么在终结者完成后没有回收对象?
答案在finalize()
的文档中:
在为对象调用
finalize
方法之后,在Java虚拟机再次确定不再有任何方法可以访问此对象之前,不会采取进一步操作[...]此时可以丢弃该对象。
因此,只要您仍然对该对象有强烈的引用,它就永远不会被垃圾收集。
第二个问题的答案是:你将它设置为null并且它永远不会被重新分配,因为特定实例的终结器只会运行一次。这也在文档中,就在上一个引用之后:
对于任何给定对象,Java虚拟机永远不会多次调用
finalize
方法。
答案 2 :(得分:0)
在对象的生命周期中,它将经历可达 - > finalizable-> finalized->回收阶段。在执行finalize()方法之后,对象将进入最终阶段,并等待下一个gc触发器,它将被回收。所以在生命周期中,finalize()方法只会被激活一次。您的SAVE_HOOK是一个静态变量,它再次在finalize()方法中赋值。这就是为什么在第一个if块中,它不是空的。但第二次,它已经死了。