泥陶匠
2016-04-02 16:05
采纳率: 0%
浏览 2.1k

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

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

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • threenewbee 2016-04-02 16:07

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

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

相关推荐 更多相似问题