G1(Garbage First)收集器是当今收集器技术发展的最前沿成果之一,他是一款面向服务端的垃圾收集器,它的使命是(在比较长期的)未来可以替换掉CMS收集器。它的特点如下:
1、并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短stop the word停顿时间,不分其他收集器原本需要停顿java线程执行的GC操作,G1收集器仍然可以通过并发的方式让java程序继续执行。
2、分代收集:与其他收集器一样,分代概念在G1中依然得到保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获得更好的收集效果。
3、空间整合:与CMS的“标记-清理”算法不同,G1从整体上来看是基于“标记-整理”算法实现的收集器,从局部(两个region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法意味着G1在运作期间不会产生内存碎片,收集后能提供规整的可用内存。
4、可预测的停顿:这个G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集伤的时间不得超过N毫秒。
在G1之前其他收集器的范围都是整个新生代或者老年代,而G1不再是这一年。使用G1收集器时,java堆的内存布局就与其他收集器有很大差别,他将整个java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是无力隔离的了,他们都是一部分Region(不需要连续)的集合。
G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划的避免在整个java堆中进行全区域垃圾收集。G1跟踪各个region里面的垃圾堆积的价值大小(回收所获的的空间大小以及回收所需时间的经验值),在后台维护一个有限列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage First名称的由来)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。
G1把内存“化整为零”的思路,理解起来似乎很容易,但其中的实现细节却远远没有想象中那样简单。例如:把java堆分为多个region后,垃圾收集是否就真的能以region为单位进行了?听起来顺利成长,但是仔细想想很容易发现问题所在:region不可能是孤立的。一个对象分配在某个region中,他并非只能被本region中的其他对象引用,而是与整个java堆任意的对象发生引用关系。那再做可达性判定确定对象是否存活的时候,。还需要扫描整个java堆才能保证准确性,这个问题并非只在G1中才有,只是在G1中更加突出而以。
在G1收集器中,region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描的。G1中每个region都有一个与之对应的emembered Set,虚拟机发现程序在对Reference类型的数据进行写操作时,会产生u 一个Write Barrier暂时终端写操作,检查Reference引用对象是否处于不同的Region之中(在分代的例子中就是检查是否老年代中的对象引用了新生代中的对象),如果是,便通过CardTable把相关引用信息记录到被引用对象所属的regipn的Remembered Set之中。当进行内存回收时,在GC根结点的枚举范围中加入Rememberd Set即可保证不对全堆扫描也不会有遗漏。
如果不计算维护Remembered Set的操作,G1收集器的运作大致可划分为以下几个步骤:
1、初始标记(Initial Marking)
2、并发标记(Concurrent Marking)
3、最终标记(Final Marking)
4、筛选回收(Live Data Counting and Evacuation)
了解CMS收集器运作的话,会发现G1的前几个步骤的运作过程和CMS有很多相似之处。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行是,能在正确可用的region中创建新对象,这阶段需要线程停顿,但耗时很短。并发标记是从GC Roots开始对堆中对象进行可达性分析,找出存活对象,这阶段耗时较长,但可与用户线程并发执行。而最终标记阶段则是为了修正在并发标记期间因用户线程记性运作而导致标记产生变化的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Log的数据合并到Remembered Set 中,这几段需要停顿线程,但是可并行执行。最后在筛选回收阶段首先对各个region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个歌阶段理论上也可以做到与用户线程并发执行,但是因为只回收一部分region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率,如下图可以比较清除的看到G1收集器运作的步骤中并发和需要停顿的阶段。
G1收集器运行示意图