为什么jvm不使用引用计数算法来判断对象是否已经死亡

在堆里面存放着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 jvm;

/**
 * testGC()方法执行后,objA和objB会不会被GC呢? 
 * @author zzm
 */
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();
    }

    public static void main(String[] args) {
        testGC();
    }
}

运行结果:

[GC (System.gc()) [PSYoungGen: 9339K->728K(76288K)] 9339K->736K(251392K), 0.0014355 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 728K->0K(76288K)] [ParOldGen: 8K->603K(175104K)] 736K->603K(251392K), [Metaspace: 3126K->3126K(1056768K)], 0.0056871 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 76288K, used 1966K [0x000000076b500000, 0x0000000770a00000, 0x00000007c0000000)
  eden space 65536K, 3% used [0x000000076b500000,0x000000076b6eba28,0x000000076f500000)
  from space 10752K, 0% used [0x000000076f500000,0x000000076f500000,0x000000076ff80000)
  to   space 10752K, 0% used [0x000000076ff80000,0x000000076ff80000,0x0000000770a00000)
 ParOldGen       total 175104K, used 603K [0x00000006c1e00000, 0x00000006cc900000, 0x000000076b500000)
  object space 175104K, 0% used [0x00000006c1e00000,0x00000006c1e96c60,0x00000006cc900000)
 Metaspace       used 3136K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 343K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值