垃圾回收:可达性分析算法、生存还是死亡(两次标记)

编程

可作为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 execute

i am still alive

i am dead

以上是 垃圾回收:可达性分析算法、生存还是死亡(两次标记) 的全部内容, 来源链接: utcz.com/z/515190.html

回到顶部