介绍
G1 GC,全称Garbage-First Garbage Collector,通过-XX:+UseG1GC参数来启用。G1收集器是工作在堆内不同分区上的收集器,分区既可以是年轻代也可以是老年代,同一个代的分区不需要连续。并且每个代分区的数量是可以动态调整的。为老年代设置分区的目的是老年代里有的分区垃圾多,有的分区垃圾少,这样在回收的时候可以专注于收集垃圾多的分区,这也是G1名称的由来。不过这个算法并不适合新生代垃圾收集,因为新生代的垃圾收集算法是复制算法,但是新生代也使用了分区机制主要是因为便于代大小的调整。
G1 GC是设计用来取代CMS的,同CMS相比G1有以下优势:
1、可预测的停顿模型
2、避免了CMS的垃圾碎片
3、超大堆的表现更出色
G1关键概念
Region
G1里面的Region的概念不同于传统的垃圾回收算法中的分区的概念。G1默认把堆内存分为1024个分区,后续垃圾收集的单位都是以Region为单位的。Region是实现G1算法的基础,每个Region的大小相等,通过-XX:G1HeapRegionSize参数可以设置Region的大小。如下图所示:
图中的E代表是Eden区,S代表Survivor,O代表Old区,H代表humongous表示巨型对象(大小大小Region空间一半的对象)。从图中可以看出各个区域逻辑上并不是连续的。并且一个Region在某一个时刻是Eden,在另一个时刻就可能属于老年代。G1在进行垃圾清理的时候就是将一个Region的对象拷贝到另外一个Region中。
SATB
SATB的全称是Snapchat-At-The_Beginning。SATB是维持并发GC的一种手段。G1并发的基础就是SATB。SATB可以理解成在GC开始之前对堆内存里的对象做一次快照,此时活的对象就认为是活的,从而形成一个对象图。在GC收集的时候,新生代的对象也认为是活的对象,除此之外其他不可达的对象都认为是垃圾对象。
如何找到在GC的过程中分配的对象呢?每个region记录着两个top-at-mark-start(TAMS)指针,分别为prevTAMS和nextTAMS。在TAMS以上的对象就是新分配的,因而被视为隐式marked。通过这种方式我们就找到了在GC过程中新分配的对象,并把这些对象认为是活的对象。
解决了对象在GC过程中分配的问题,那么在GC过程中引用发生变化的问题怎么解决呢, G1给出的解决办法是通过Write Barrier。Write Barrier就是对引用字段进行赋值做了环切。通过Write Barrier就可以了解到哪些引用对象发生了什么样的变化。