生存还是死亡
C++必须手动释放内存, 而Java有Garbage Collection(垃圾回收机制), 自动释放内存, 那么gc是如何判断一个对象是否已经死亡, 是否该回收它了? 这就需要一个垃圾回收算法
可达性分析算法
在Java中使用的是可达性分析算法, 就是对象到gc roots是否直接或者间接性可达, 可达就还活着, 不可达就是死了, 要回收了
在这张图中, Object1、Object2、Object3是连在GC Roots上的, 而Object4没有, Object4就很有可能快被gc回收了
什么是finalize方法
finalize英文是终结的意思, 我认为这个方法可以理解为每个对象的"最后遗言", 快要被gc回收前执行的方法 ,不过有没有说遗言的机会还不一定呢…
执行finalize方法的时机
由于垃圾回收的不确定性, gc不能保证一个对象的finalize方法一定会被执行, 即便是System.gc()亦或者是System.runFinalization()也仅仅是提醒JVM要进行垃圾回收了, 仅仅是个建议, 到底要不要执行, 还是JVM说了算
一个对象死亡消失前, 至少要被标记两次, 第一次就是JVM通过可达性算法检测到它无法连接到gc roots, 如上面的Object4, 它会被标记一次并放入一个即将送往"断头台"的队列中, 如果这个对象没有重写finalize方法或者已经执行过finalize方法,它就会被标记第二次,基本死翘翘了.
所以,finalize必须要重写才有可能执行, 而且最多只会执行一次.
那假如我们在finalize方法中让对象重新连接上GC Roots, 那不就可以救活它了吗?finalize方法好比是它一块唯一的、一次性的"免死金牌",像是电视里面骑着马赶来大喊一声"刀下留人"的场景, 有没有点像, 哈哈
实现对象的自我拯救
public class FinalizeDemo {
//声明一个引用
private static FinalizeDemo finalizeDemo = null;
//判断对象是否可达gc roots
public static void isAlive() {
if (FinalizeDemo.finalizeDemo != null) {
System.out.println("我还活着!");
} else {
System.out.println("我死了..");
}
}
@Override
protected void finalize() throws Throwable {
//把自身赋值给声明的引用,连接上gc roots
finalizeDemo = this;
System.out.println("连上GC roots, 抓住了救命稻草!");
}
public static void main(String[] args) {
//new一个对象,对gc roots不可达, 即将面临死亡
new FinalizeDemo();
//建议gc进行垃圾回收,并执行finalize方法
System.gc();
System.runFinalization();
//看看它死了还是活着
FinalizeDemo.isAlive();
//断开和gc roots的连接,现在为不可达
finalizeDemo = null;
System.gc();
System.runFinalization();
FinalizeDemo.isAlive();
}
}
在主方法中,new了一个即将面临被回收的对象, 它通过finalize方法连接上gc roots才捡回了一命,当它断开连接后, 又面临着即将被回收的命运, 本想再次调用finalize方法救自己, 可是它的finalize方法已经被执行过一次了, 不会再执行了,所以只能"死亡"了
运行结果: