G1(Garbage-First)回收器是在JDK1.7中正式使用的全新垃圾回收器,G1拥有独特的垃圾回收策略,从分代上看,G1依然属于分代垃圾回收器,它会区分年代和老年代,依然有eden和survivor区,但从堆的结构上看,它并不要求整个eden区、年清代或者老年代都连续。它使用了全新的分区算法。其特点如下:
l 并行性:G1在回收期间,可以由多个GC线程同时工作,有效利用多核计算能力。
l 并发性:G1拥有与应用程序交替执行的能力,因此一般来说,不会在整个回收期间完全阻塞应用程序。
l 分代GC:与之前回收器不同,其他回收器,它们要么工作在年轻代要么工作在老年代。G1可以同时兼顾年轻代与老年代。
l 空间整理:G1在回收过程中,会进行适当的对象移动,不像CMS,只是简单的标记清除,在若干次GC后CMS必须进行一次碎片整理,G1在每次回收时都会有效的复制对象,减少空间碎片。
l 可预见性:由于分区的原因,G1可以只选取部分区域进行内存回收,这样缩小了回收范围,因此对于全局停顿也能得到更好的控制。
G1的内存划分和主要收集过程
G1的收集过程可能有4个阶段:1.新生代GC 2.并发标记周期 3.混合收集 4.如果需要,可能会进行fullGC。
1.G1新生代GC
新生代GC只处理eden和survivor区,回收后所有eden区域都应该清空,survivor区会被清空一部分数据,但是应该至少存在一个survivor区。
2. G1的并发标记周期
l 初始标记:标记从根节点直接可达的对象。这个阶段会伴随一次新生代GC,它是会产生全局停顿的。
l 根区域扫描:由于初始标记必然会产生一次新生代GC,所以在初始标记后,eden被清空,并且存活对象移入survivor区。在这个阶段将扫描由survivor区直接可达的老年代区域,并标记这些直接可达的对象,这个过程是可以和应用程序并发执行的。
l 并发标记:和CMS类似,并发标记会扫描并查找整个堆的存活对象,并做好标记。这是一个并发的过程,并且会被新生代GC打断。
l 重新标记:和CMS标记一样,重新标记会产生一次卡顿。由于并发标记过程中,应用程序依然在运行,因此标记结果可能需要修正(程序在运行eden区有可能进入新的对象),所以在此对上一次的标记结果进行补充。在这个过程中使用SATB(Snapshot At The Beginning)算法完成,即G1会在标记之初为存活对象春哥见一个快早,这个快早有助于加速重新标记速度。
l 独占清理:这个阶段会引起程序卡顿。它将计算各个区域的存活对象和GC回收比例并进行排序,识别可供混合回收的区域。还会更新记忆集(RemebereSet)。该阶段给出了需要被混合回收的区域并进行了标记。
l 并发清理:这个阶段会识别并清理完全空闲的区域,他是并发清理的,不会引起卡顿。
3.混合回收
在并发标记周期中,虽然有部分对象被回收,但是总体上这部分回收的比例是相当低的。但是在并发标记后,G1已经明确知道哪些区域含有比较多的垃圾对象,在混合回收阶段可以专门针对这些区域进行回收。这个阶段即会执行正常的年轻代Gc又会选取一些被标记的老年代区域进行回收,它同事处理了新生代和老年代。混合Gc会执行多次,知道回收了足够多的内存空间,之后会触发一次新生代GC。新生代GC后又可能触发一次并发标记周期,最后又引起混合GC的执行。
4.必要时的FullGC
和CMS类似,并发收集器由于让应用程序与GC线程交替执行,因此总是不能避免在特别繁忙的场景会出现在回收过程中内存不足的情况,当遇到这种情况时G1也会转入一个FullGC回收。此外如果在混合GC发生空间不足或者新生代GC时,survivor区和老年代无法容纳幸存对象,都会导致一次FullGC。