JVM-018-对象已死-引用计数算法

  • 在堆里面存放着Java世界中几乎所存的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象)。
  • 很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。作者面试过很多的应届生和一些有多年工作经验的开发人员,他们对于这个问题给予的都是这个答案。
  • 客观地说,引用计数算法(Reference Counting)的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软公司的COM(Component Object Model)技术、使用ActionScript 3的FlashPlayer、Python语言和在游戏脚本领域被广泛应用的Squirrel中都使用了引用计数算法进行内存管理。但是,至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。
  • 举个简单的例子,下面代码中的testGC()方法:对象objA和objB都有字段instance,赋值令objA.instance=objB及objB.instance=objA,除此之外,这两个对象再无任和引用,实际上这两个对象已经不可能再被访问,但是它们因为互相引用着对方,导致它们的引用计数都不为0,于是引用计数算法无法通知GC收集器回收它们。
package top.itcourse.jvm;

public class ReferenceCounting {

    public Object instance = null;

    private static final int _1MB = 1024*1024;

    /*
     * 这个成员的意义:占点内存,以便在GC日志中能看清是否被回收过
     */
    private byte[] bigSize = new byte[2 * _1MB];


    public static void testGC() {
        ReferenceCounting objA = new ReferenceCounting();
        ReferenceCounting objB = new ReferenceCounting();

        objA.instance = objB;
        objB.instance = objA;

        objA = null;
        objB = null;

        // objA和objB是否会被回收?
        System.gc();
    }

    /*
     * 参数:
     *  -verbose:gc         // 打印垃圾回收的日志信息,简单信息
     *  -xx:+PrintGCDetail  // 详细信息 
     */
    public static void main(String[] args) {
        ReferenceCounting.testGC();
    }
}

  • 从运行结果中可以清楚看到,GC日志中包含“4603K->210K”,意味着虚拟机并没有因为这两个对象互相引用就不回收它们,这也从侧面说明虚拟机并不是通过引用计数算法来判断对象是否存活的。


其它



源码下载:

关注下方微信公众号,
回复:
JVM.code
  • 欢迎加入交流群:451826376

  • 更多信息:www.itcourse.top

你可能感兴趣的:(JVM_教程版)