引用计数算法Reference Counting:给对象添加一个引用计数器,每当被引用一次的时候计数器值+1,当引用失效时计数器值-1,任何时刻计数器为0的对象就是不可能再被使用的。存在问题:解决不了对象之间相互循环引用的问题
public class ReferenceCountingGC {
public Object instance;
public static void main(String[] args) throws InterruptedException {
ReferenceCountingGC refA = new ReferenceCountingGC();
ReferenceCountingGC refB = new ReferenceCountingGC();
refA.instance = refB;
refB.instance = refA;
refA = null;
refB = null;
System.gc();
Thread.sleep(10000); //gc回收需要时间
}
@Override
protected void finalize() throws Throwable {
System.out.println("被回收前执行finalize,finalize方法优先级很低");
super.finalize();
}
}
可达性分析算法Reachability Analysis:将GC Roots对象作为起始点,从这些起始点开始往下搜索,搜索所走过的路径称之为引用链Reference Chain,当一个对象到GC Roots没有任何引用链相连时则说明此对象是不可达的,需要被gc回收
GC Roots包含:虚拟机栈(栈帧中的本地变量表)中引用的对象;
方法区中静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(native方法)引用的对象
finalize()方法最终判定对象是否存活
即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历再次标记过程
标记的前提是对象在进行可达性分析后发现没有与GC Roots相连接的引用链。
1. 第一次标记并进行一次筛选。
筛选的条件是此对象是否有必要执行finalize()方法。
当对象没有覆盖finalize方法,对象将直接被回收。
2. 第二次标记
如果这个对象覆盖了finalize方法,finalize方法是对象脱逃死亡命运的最后一次机会,如果对象要在finalize()中成功拯救自己,只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己赋值给某个类变量或对象的成员变量,那在第二次标记时它将移除出“即将回收”的集合。如果对象这时候还没逃脱,那基本上它就真的被回收了
注意:一个对象的finalize()方法只会被执行一次,也就是说通过调用finalize方法自我救命的机会就一次。
对象自救:
public class FinalizeEscapeGC {
private static FinalizeEscapeGC SAVE_HOOK = null;
public static void main(String[] args) {
SAVE_HOOK = new FinalizeEscapeGC();
SAVE_HOOK = null;
System.gc();
try {
Thread.sleep(2000); //finalize优先级低,暂停2s等待gc
} catch (InterruptedException e) { e.printStackTrace(); }
if (SAVE_HOOK != null) { System.out.println("i am still alive!");
} else { System.out.println("sorry, i am not alive"); }
SAVE_HOOK = null;
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (SAVE_HOOK != null) { System.out.println("i am still alive!");
} else { System.out.println("sorry, i am not alive");}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("对象在被gc时可以自我拯救,这种自救的机会只有一次,因为一个对象的finalize方法最多只会被系统自动调用一次");
SAVE_HOOK = this;
}
}
打印结果如下:
对象在被gc时可以自我拯救,这种自救的机会只有一次,因为一个对象的finalize方法最多只会被系统自动调用一次
i am still alive!
sorry, i am not alive