分析
要真正回收掉一个对象,至少要经过两次标记过程。具体过程可以见JVM垃圾回收的分析文章。
如果对象在进行可达性分析后发现没有与GC Roots
相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()
方法。当对象没有覆盖(重写)finalize()
方法或者finalize()
方法已经被虚拟机调用过,虚拟机将这两种情况视为"没有必要执行"。
下面的代码演示了如何通过覆盖finalize()
防止对象自己被第一次垃圾回收。
GC的时候,第一次调用finalize()
,又由于在finalize()
方法中,将自己的对象引用this传给了静态变量SAVE_HOOK,所以第一次没有被回收。但是finalize()
方法只会被调用一次,第二次,当SAVE_HOOK再次NULL的时候,该对象就被回收了。
代码
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println("Now, I am alive!");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("Finalize method executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws InterruptedException {
SAVE_HOOK = new FinalizeEscapeGC();
SAVE_HOOK = null;
System.gc();
// finalize方法的优先级很低,此处暂停0.5s来等待它
Thread.sleep(500);
if (SAVE_HOOK!=null){
SAVE_HOOK.isAlive();
}else{
System.out.println("Ops, i am dead");
}
SAVE_HOOK=null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK!=null){
SAVE_HOOK.isAlive();
}else{
System.out.println("Ops, i am dead");
}
}
}
运行结果
Finalize method executed!
Now, I am alive!
Ops, i am dead
网友评论