垃圾收集器与内存分配策略:
对象已死吗
在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中那些还“存活”着,哪些已经“死去”(即不能再被任何途径使用的对象)。
引用计数算法
很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。
客观地说,引用技术算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软公司的COM技术、使用ActionScript3的FlashPlayer、Python语言和在游戏脚本领域被广泛应用的Squirrel中都使用了引用计数算法进行内存管理。但是,至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它难以解决对象之间的相互循环引用的问题。
public class ReferenceCountingGC { public Object instance = null; private static final int _1MB = 1024 * 1024; private byte[] bigSize = new byte[2 * _1MB]; /** * -XX:+PrintGCDetails * @param args */ public static void main(String[] args){ ReferenceCountingGC obj1 = new ReferenceCountingGC(); ReferenceCountingGC obj2 = new ReferenceCountingGC(); obj1.instance = obj2; obj2.instance = obj1; obj1 = null; obj2 = null; System.gc(); } }
obj1.instance = obj2
obj2.instance = obj1
这两个对象再无任何引用,实际上两个对象不可能再被访问,但是它们互相引用对方,导致它们的引用计数不为0,于是引用计数算法无法通知GC收集器回收它们。
从上面的运行结果中,虚拟机并没有因为这两个对象互相引用就不回收它们,这也从侧面说明虚拟机并不是通过引用计数算法来判断对象是否存活