垃圾回收:可达性分析算法、生存还是死亡(两次标记)
可作为GC ROOTS
的对象有:
虚拟机栈中的本地标量表
方法区中类的静态属性
方法区中常量
本地方法区中引用的对象
前两个是主要的。
下面详细说:
判断哪些内存需要回收
引用计数算法、可达性分析算法。引用计数算法优点实现简单,但是无法判断循环引用。
可达性分析算法:通过一系列的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 executei am still alive
i am dead
以上是 垃圾回收:可达性分析算法、生存还是死亡(两次标记) 的全部内容, 来源链接: utcz.com/z/515190.html