以下内容自sun白皮书1-150020中找到,由于加上我自己的理解,所以不是翻译文章(英语不给力,翻译不好).其中我只关注了回收的抽象机制,对于引用计数,具体算法等未涉及.
hotspot(j2se 5.0,按白皮书上的说法也适用于6.0)使用的是所谓的Generational Collection机制,也就是把对象分为young和old(还有一种是permanent,暂时不鸟他),young对象经过几次回收后(存活较长时间后),就会成为old对象.之所以采用这种机制,是基于以下观察:大部分新建对象的引用不会持续太久,也就说是会die young;少部分的引用会持续下来.
因此,young generation进行Collection会更多,因此使用的算法对时间效率的要求高.而old generation 保存的数据较多,使用的算法对空间的要求效率相对而言要求就较高了.把对象分为不同的generation,便于采用不同的算法进行操作.
对应的,可以把HotSpotJVM 的内存分为:young generation ,oldgeneration ,permanent generation.在这里默认首先把对像都放到区域的左边.
J2SEHotSpot JVM的 4中垃圾回收器都是属于generational collection.
一般说来,新建对象时一般都是在young里面分配内存,old里面储存的是young中经过几次回收依然存活的对象以及一些一开始就在old中分配的大对象.而permanent generation里面保存的是类信息和元数据.
younggeneration分为一个Eden区域和两个survivor区域.对象在Eden区域生成,经过一次GC后存活下来的对象进入survivor中,并在此经过更严格的考验,然后进入old .同一时间只有一个survivor区域保存对象,另一个为空.
当young区域满了后,就会执行young区域的GC算法.当old和permanent区域满了后,会先执行young的GC.再执行old和permanent的GC,如果old区域对象过多无法执行young的GC,那么在young区域执行old的GC算法(因为内存空间耗费较少),但是CMS回收器的old算法不行,下面会说明原因.
对于多线程的应用.JVM使用一个Thread-LocalAllocation Buffers ,为每个线程分配一个区域来分配对象,以排除线程竞争.如果此区域满了的话就使用锁.
HotSpot的四种GC回收器:
串行化回收serial collector:
特点:回收时会暂停应用.
young区域:将Eden和某个Survivor区域中的存活的对象复制到另一个Survivor区域(设为TO)(大对象直接放到old区域).如果TO区域满了,则直接复制到old区域.
old区域:使用mark-sweep-compact GC算法,也就是先标记存活对象,然后清除废弃对象,然后把存活对象都移到一块区域,空出一片较大的空闲空间.
适用范围:大部分客户端的应用都可以使用这种回收算法,这也是HotSpot默认的回收算法.在现在的机器(06年)上一个64MB的区域的一次完全回收所需的时间不到半秒钟.
并行回收parallel collector:
特点:可以利用多核的CPU.
young区域:同样还是要暂停应用,基本机制和串行化差不多,不过是使用多线程.可以加快效率.
old区域:同串行化.
多核计算机上面可以使用.
并行压缩回收parallel compacting collector:
与并行回收相比,主要是在old区域有个新的算法,同时,按白皮书的说法,这种回收最终会替代并行回收.
young区域:同并行回收.
old区域:首先,把old分为几个连续的区域.然后,在每个区域并行的进行检查,标记出alive的对象(先标记出可以直接引用的对象,然后是所有的).然后开始对这些区域进行检查,得出密集程度(左边的区域肯定比右边的密集),从某个密集程度不很高的区域开始,并行的对右边区域进行压缩.
适应范围:对于多核,且对pause time有要求的环境下,使用并行压缩回收比并行回收要好.但是对于高共享率的服务器(也就说一台服务器运行多个应用),由于old区域的collection较慢,又是多线程,所以一个应用的GC会对其他应用造成影响.对应的解决方法:可以配置减少并行时的线程数目.
并行标记清除回收Concurrent Mark Sweep collector:
young区域:同并行回收.
old区域:分为几个步骤.
Initialmark:在需要执行GC时,先暂停应用,然后把所有直接引用到的对象进行标记.
Concurrentmark:然后继续应用,并同时对已标记对象进行检查,得到所有存活的对象.
remark:再次暂停应用,对Concurrent mark持续期间应用程序修改了的对象进行检查(新增的,废弃的),并标记存活对象.这个阶段持续时间较长,因此会使用多线程.在阶段结束后,所有的存活对象都被标记了,未标记的对象就是垃圾对象了.
sweep:停止暂停应用程序,然后把所有垃圾对象的空间释放.
与其他算法的不同点:
第一:不执行压缩.不过会通过计算将来可能的内存需求而合并/分割某些内存块.
第二:不是old区域要满了才执行GC,而是在空间小于一定程度时开始.
第三:由于没执行压缩,因此会产生碎片.
另外,CMS还可以使用增量运行方式,就是在Concurrentmark阶段只执行一部分工作,然后把资源还给应用程序.回收器的工作会分为几个部分并安排在两次young区域的回收空闲阶段完成.这种模式一般用在对暂停时间有要求,同时处理器数目不多的情况下(单核或双核).
总体说来,与并行回收相比,CMS降低了old GC的暂停时间(有时候效果很显著),轻微的加长了young GC的时间(因为对象从young区域转到old区域时间会加长:没执行压缩,因此要先找到合适的区域),降低了整个系统的一些执行效率,以及很大的加强了对于内存空间的需求.
适用范围:对暂停时间有要求,服务器能够分配一些资源给GC线程.一般说来,适用于应用相对而言有一些比较大的old generation,并且是多核处理器的服务器.比如说web server(这里特别指明web server了)