判断哪些内存需要回收
引用计数算法、可达性分析算法。引用计数算法优点实现简单,但是无法判断循环引用。
可达性分析算法:通过一系列的GC ROOTS作为起点,往下搜索,所走过的路径叫引用链。当一个对象没有引用链到GC ROOTS上,则可以回收。
finalize 自救
finalize被执行,对象不一定被回收
一个对象宣布死亡,需要两次标记
第一次:没有与GC ROOTS相连接。finalize方法被覆盖并且没有调用过,则进入F-Queue队列。这个是在优先级低的finalizer线程执行,不保证等待线程结束。如果其中一个运行太久,其他对象的finalize会一直等待。
finalize是完成自救的最后机会。可以把this复制给GC ROOTS,避免第二次标记时被回收。不一定能救,因为优先级低
第二次:判断第一次标记的对象中,是否还是没有与GC ROOTS连接。如归是则回收,并且不会执行finalize(要么已经在第一次标记时执行,要么没有覆写)
不过finalize方法已经是Deprecated,由于可能导致性能,死锁和挂起等问题将会被移除。
例子
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public static void main(String[] args) throws Exception {
SAVE_HOOK = new FinalizeEscapeGC();
SAVE_HOOK = null;
// 这两句保证进行垃圾回收标记, finalize能进行挽救自己
System.gc();
Thread.sleep(500);
if (SAVE_HOOK == null) {
System.out.println("i am dead");
} else {
// 这里被执行,成功挽救自己
System.out.println("i am still alive");
}
// 一样的的代码
SAVE_HOOK = null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK == null) {
// 这里被执行, 无法挽救,finalize只能执行一次
System.out.println("i am dead");
} else {
System.out.println("i am still alive");
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
SAVE_HOOK = this;
System.out.println("finalize execute");
}
}
输出:
finalize execute
i am still alive
i am dead