“ 被JVM标记为已死的对象还可以自己救活自己?”
这是一个面试题,大概就是一个对象被GC的话会直接将它清理掉吗?
那既然都这么问了,那肯定是不会了。
众所周知Object是所有类的基类,它里面就有一个finalize方法,在执行GC的时候他会先去执行这个方法,但只会执行一次,在下面我们写几行代码证明一下。
证明GC会执行finalize方法
public class GCDemo {
private static GCDemo gcDemo = new GCDemo();
@Override
protected void finalize() throws Throwable {
System.out.println("finalize方法被执行");
}
public static void main(String[] args) throws InterruptedException {
gcDemo = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
}
}
运行结果:
证明finalize只会被执行一次
public class GCDemo {
private static GCDemo gcDemo = new GCDemo();
@Override
protected void finalize() throws Throwable {
System.out.println("finalize方法被执行");
}
public static void main(String[] args) throws InterruptedException {
gcDemo = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
gcDemo = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
}
}
运行结果:
对象如何进行自救
public class GCDemo {
private static GCDemo gcDemo = new GCDemo();
@Override
protected void finalize() throws Throwable {
System.out.println("尝试自救");
gcDemo = this;
System.out.println("自救成功");
}
public static void main(String[] args) throws IOException, InterruptedException {
gcDemo = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(gcDemo);
gcDemo = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(gcDemo);
}
}
运行结果:
这儿我发现第一次GC调用了finalize将对象重新赋值为当前对象,而第二次GC没有执行,所以输出为null。
当然,对象的值为null不能证明对象已经被回收了,我们可以使用jmap命令来打印当前存活的对象
jmap -histo:live pid
自己去操作
其实Java并不推荐这样子做,上面代码只是演示,在JDK9中已经将此方法标上@Deprecated注解,表示过期方法