垃圾回收机制

一、概述

说起垃圾收集(Gargbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物,事实上,GC的历史比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.当Lisp还在胚胎的时期时,人们就在思考GC需要完成的3件事情:

1 哪些内存需要回收?

2 什么时候回收?

3 如何回收?

经过半个多世纪的发展,目前内存的动态分配与内存回收技术已经相当成熟,一切看起来都进入了"自动化"时代,那为什么我们还要去了解GC和内存分配呢?答案很简单:当需要排查各种内存溢出,内存泄漏问题 时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些"自动化"的技术实施必要的监控和调节.

 

二、对象回收机制算法

1 引用计数算法

很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1; 当引用失效时,计数器值就减1; 任何时刻计数器为0的对象就是不可能再被使用的. 客观地说,引用计数算法(Reference Counting)的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软公司的COM(Component Object Model)技术,使用ActionScript3的FlashPlayer,Python语言和在游戏脚本领域被广泛应用的Squirrel中都使用了引用计数算法进行内存管理.但是,至少主流的Java虚拟机里没有选用引用计算算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题, 虽然两个对象内部都使用引用指向对方对象, 但A,B对象已经没有了外部引用指向它们, 显然这两个对象应当被回收,但是如果使用计数算法,显然是无能无力的.

2 可达性分析算法

在主流的商用程序语言(Java, C#,甚至包括前面提到的古老的Lisp)的主流实现中,都是通过可达性分析(Reachablity Analysis)来判定对象是否存活的.这个算法的基本思想就是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的.  这样, 虽然有些对象内部仍然有引用在互相引用,但是如果通过GC Roots不能到达它们, 它们就仍然会被判定为是垃圾对象.