Java虚拟机读书笔记

3.2 对象已死吗(判断对象是否能回收)

2017-07-31  本文已影响0人  MoscowAug

3.2.1 引用计数算法

对象objA和objB都有字段 instance,赋值令objA.instance=objB及objB.instance=objA,除此之外,这两个对象再无任何引 用,实际上这两个对象已经不可能再被访问,但是它们因为互相引用着对方,导致它们的引 用计数都不为0,于是引用计数算法无法通知GC收集器回收它们

/**
 * testGC()方法执行后,objA和objB会不会被GC呢?
 */
public class ReferenceCountingGC {
    public Object instance = null;
    private static final int _1MB = 1024 * 1024;
    /**
     * 这个成员属性的唯一意义就是占点内存,以便能在GC日志中看清楚是否被回收过
     */
    private byte[] bigSize = new byte[2 * _1MB];

    public static void testGC() {
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;
        objA = null;
        objB = null; //假设在这行发生GC,objA和objB是否能被回收?
        System.gc();
    }
}

3.2.2 可达性分析算法

可达性分析算法判定对象是否可回收

对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达 的,所以它们将会被判定为是可回收的对象。

在Java语言中,可作为GC Roots的对象包括下面几种:

3.2.3 再谈引用

Java对引用类型分为以下四种,这4种引用强度依次逐渐减弱:

3.2.4 生存还是死亡

可达性算法计算、回收过程:
/**
 * 此代码演示了两点:
 * 1.对象可以在被GC时自我拯救。
 * 2.这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次
 */
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 mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();
        //对象第一次成功拯救自己
        SAVE_HOOK = null;
        System.gc();
        //因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead:(");
        }
        //下面这段代码与上面的完全相同,但是这次自救却失败了
        SAVE_HOOK = null;
        System.gc();
        //因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead:(");
        }
    }
}

运行结果:
finalize mehtod executed!
yes,i am still alive:)
no,i am dead:(

从代码中可以看到一个对象的finalize()被执行,但是它仍然可以存活。
代码中有两段完全一样的代码片段,执行结果却是一次逃 脱成功,一次失败,这是因为任何一个对象的finalize()方法都只会被系统自动调用一次, 如果对象面临下一次回收,它的finalize()方法不会被再次执行,因此第二段代码的自救行动失败了。

3.2.5 回收方法区

永久代的垃圾收集主要回收两部分内容:废弃常量无用的类

虚拟机可以对满足上述3个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样,不使用了就必然会回收。是否对类进行回收,HotSpot虚拟机提供了-Xnoclassgc 参数进行控制,还可以使用-verbose:class以及-XX:+TraceClassLoading、-XX: +TraceClassUnLoading查看类加载和卸载信息,其中-verbose:class和-XX: +TraceClassLoading可以在Product版的虚拟机中使用,-XX:+TraceClassUnLoading参数需要 FastDebug版的虚拟机支持。 在大量使用反射、动态代理、CGLib等ByteCode框架、动态生成JSP以及OSGi这类频繁 自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出

上一篇 下一篇

猜你喜欢

热点阅读