中国领先的IT技术网站
|
|

3.2.1 引用计数算法

《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》第3章垃圾收集器与内存分配策略,本章介绍了垃圾收集的算法、几款JDK 1.7中提供的垃圾收集器特点以及运作原理。通过代码实例验证了Java虚拟机中自动内存分配及回收的主要规则。本节为大家介绍引用计数算法。

作者:周志明来源:机械工业出版社|2013-06-18 14:15

Tech Neo技术沙龙 | 11月25号,九州云/ZStack与您一起探讨云时代网络边界管理实践


3.2 对象已死吗

在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象)。

3.2.1 引用计数算法

很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。作者面试过很多的应届生和一些有多年工作经验的开发人员,他们对于这个问题给予的都是这个答案。

客观地说,引用计数算法(Reference Counting)的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软公司的COM(Component Object Model)技术、使用ActionScript 3的FlashPlayer、Python语言和在游戏脚本领域被广泛应用的Squirrel中都使用了引用计数算法进行内存管理。但是,至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。

举个简单的例子,请看代码清单3-1中的testGC()方法:对象objA和objB都有字段instance,赋值令objA.instance = objB及objB.instance = objA,除此之外,这两个对象再无任何引用,实际上这两个对象已经不可能再被访问,但是它们因为互相引用着对方,导致它们的引用计数都不为0,于是引用计数算法无法通知GC收集器回收它们。

代码清单3-1 引用计数算法的缺陷

  1. /**  
  2.  * testGC()方法执行后,objA和objB会不会被GC呢?  
  3.  * @author zzm  
  4.  */  
  5. public class ReferenceCountingGC {  
  6.  
  7.   public Object instance = null;  
  8.  
  9.   private static final int _1MB = 1024 * 1024;  
  10.  
  11.   /**  
  12.    * 这个成员属性的唯一意义就是占点内存,以便能在GC日志中看清楚是否被回收过  
  13.    */  
  14.   private byte[] bigSize = new byte[2 * _1MB];  
  15.  
  16.   public static void testGC() {  
  17.    ReferenceCountingGC objA = new ReferenceCountingGC();  
  18.    ReferenceCountingGC objB = new ReferenceCountingGC();  
  19.    objA.instance = objB;  
  20.    objB.instance = objA;  
  21.  
  22.    objA = null;  
  23.    objB = null;  
  24.  
  25.    //假设在这行发生GC,objA和objB是否能被回收?  
  26.    System.gc();  
  27.   }  

运行结果:

  1. [Full GC (System) [Tenured: 0K->210K(10240K), 0.0149142 secs] 4603K->210K(19456K), [Perm : 2999K->2999K(21248K)], 0.0150007 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]  
  2. Heap  
  3.  def new generation   total 9216K, used 82K [0x00000000055e0000, 0x0000000005fe0000, 0x0000000005fe0000)  
  4.   Eden space 8192K,   1% used [0x00000000055e0000, 0x00000000055f4850, 0x0000000005de0000)  
  5.   from space 1024K,   0% used [0x0000000005de0000, 0x0000000005de0000, 0x0000000005ee0000)  
  6.   to   space 1024K,   0% used [0x0000000005ee0000, 0x0000000005ee0000, 0x0000000005fe0000)  
  7.  tenured generation   total 10240K, used 210K [0x0000000005fe0000, 0x00000000069e0000, 0x00000000069e0000)  
  8.    the space 10240K,   2% used [0x0000000005fe0000, 0x0000000006014a18, 0x0000000006014c00, 0x00000000069e0000)  
  9.  compacting perm gen  total 21248K, used 3016K [0x00000000069e0000, 0x0000000007ea0000, 0x000000000bde0000)  
  10.    the space 21248K,  14% used [0x00000000069e0000, 0x0000000006cd2398, 0x0000000006cd2400, 0x0000000007ea0000)  
  11. No shared spaces configured. 

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

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢
24H热文
一周话题
本月最赞

读 书 +更多

Struts 2权威指南:基于WebWork核心的MVC开发

本书所介绍的Struts 2已经完全超出了Struts 1框架原有的高度,Struts 2建立在Struts 1和WebWork两个框架整合的基础之上,因此提供了更多优...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊
× CTO训练营(深圳站)