2 csdnyoyo csdnyoyo 于 2016.04.03 00:05 提问

java垃圾回收机制GC判断可回收对象算法

java垃圾回收机制中,讲到GC判断可回收对象算法时,有一种可达性算法,不明白它如何解决对象循环引用问题的?

4个回答

wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.04.03 08:08
 本问题,摘录周志明先生的《深入理解Java虚拟机》一书中对可达性算法的分析。
首先,可达性算法基本思路是定义一些列称为"GC-Roots"的对象作为起始阶段,从这些节点向下搜索,搜索走过的路径称为引用链,当一个对象到GCRoots没有任何引用链时(即从GCRoots到这个对象不可达),则证明此对象是不可用的。
其次,可达性算法中的不可达对象,在真正宣告“死亡”需要回收之前,至少要经过两轮标记过程:如果对象不可达,会被第一次标记并且进行一次筛选,筛选条件是次对象有没有必要执行finalize()方法。
当对象没有覆盖finalize()方法或者这个方法以及被执行过了,那么久视为没有必要再执行。
对于那些有必要执行finalize()方法的对象会被放在一个队列F-Queue中,然后稍后由虚拟机的一个线程去执行逐一执行队列中对象的finalize方法,如果线程在执行过程中发生了死循环,或者某个对象的finalize方法执行时间过长,导致队列其他对象一直处于等待,那么就会导致整个内存回收系统崩溃。
第三,finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC会对F-Queue中的对象进行第二次小规模的标记,如果能在finalize中成功重新引用,第二次标记时就会将该对象从F-Queue集合中移除,而成功脱逃。
所以,我理解你说的循环引用可能是想说不可达后突然又再次引用了,那么只能在finalize方法中再次引用而救活对象了。如果是普通循环中的循环操作引用,应该还没有涉及到垃圾回收、标记不可达的时候。
最后,算法中的根对象通常是全局的静态成员对象,方法区中的常量引用对象,Native引用对象,线程栈中的引用对象等。
wojiushiwo945you
wojiushiwo945you 回复泥陶匠: 不客气,正好手边有书,查找后分享下而已!祝好!
一年多之前 回复
csdnyoyo
csdnyoyo 谢谢,基本上明白了。
一年多之前 回复
wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.04.03 08:17

附上书中一个待回收对象复活的例子:

 /**
 * 自我救赎的机会只有一次,即重新finalize并再次引用自己,
 * 因为一个对象的 finalize()方法最多只会被系统调用一次
 * @author 金涛
 *
 */
public class FinalizeEscapeGC {
    public static FinalizeEscapeGC save_hook = null;

    public void isAlive() {
        System.out.println("yes ,I am still alive.");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize method executd!");
        FinalizeEscapeGC.save_hook = this;
    }

    public static void main(String[] args) throws Throwable {
        save_hook = new FinalizeEscapeGC();

        // 设置为null,标记不可达,通知GC回收
        save_hook = null;
        System.gc();

        // 当前线程休眠5秒,让GC线程优先执行
        Thread.sleep(500);
        if (save_hook != null) {
            save_hook.isAlive();
        } else {
            System.out.println("Oh My God ,I am going to dead.Who can help me?");
        }

        // 再测试一次:下面代码与上面完全相同,但是自我救赎失败,因为finalize只会执行一次
        save_hook = null;
        System.gc();

        // 当前线程休眠5秒,让GC线程优先执行
        Thread.sleep(500);

        if (save_hook != null) {
            save_hook.isAlive();
        } else {
            System.out.println("Oh My God ,I am going to dead.Who can help me?");
        }
    }
}

你可以执行下,很有意思,执行结果为如下,只能脱逃一次,最后还是被回收了。

 finalize method executd!
yes ,I am still alive.
Oh My God ,I am going to dead.Who can help me?
wojiushiwo945you
wojiushiwo945you 第一段在finalize中自引用成功,所以save_hook.isAlive();执行了;而第二次即最后一行代码执行了,对象已经被GC回收了。
一年多之前 回复
caozhy
caozhy   Ds   Rxr 2016.04.03 00:07

循环引用并不怕,因为标记过的对象就不会再被标记,更不用说它再指向的对象了。

csdnyoyo
csdnyoyo 谢谢,我在研究下
一年多之前 回复
CSDNXIAOD
CSDNXIAOD   2016.04.07 00:50

GC判断可回收对象算法
----------------------biu~biu~biu~~~在下问答机器人小D,这是我依靠自己的聪明才智给出的答案,如果不正确,你来咬我啊!

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!