优点:指定最大停顿时间、分Region的内存布局、按收益动态确定回收集
G1开创的基于Region的堆内存布局是它能够实现这个目标的关键。虽然G1也仍是遵循分代收 集理论设计的,但其堆内存的布局与其他收集器有非常明显的差异:G1不再坚持固定大小以及 固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region), 每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。 收集器能够对扮演不同角色的Region采用不同的策略去处理,这样无论是新创建的对象还是已 经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果。
虽然G1仍然保留新生代和老年代的概念,但新生代和老年代不再是固定的了,它们都是一系列 区域(不需要连续)的动态集合。G1收集器之所以能建立可预测的停顿时间模型,是因为它将 Region作为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍,这样 可以有计划地避免在整个Java堆中进行全区域的垃圾收集。更具体的处理思路是让G1收集器去 跟踪各个Region里面的垃圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需 时间的经验值,然后在后台维护一个优先级列表,每次根据用户设定允许的收集停顿时间(使 用参数-XX:MaxGCPauseMillis指定,默认值是200毫秒),优先处理回收价值收益最大的 那些Region,这也就是“Garbage First”名字的由来。这种使用Region划分内存空间,以及 具有优先级的区域回收方式,保证了G1收集器在有限的时间内获取尽可能高的收集效率。
G1收集器的运作过程大致可划分为以下四个步骤: ·
初始标记 (Initial Marking):仅仅只是标记一下GC Roots能直接关联到的对象,并且修改 TAMS指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象。 这个阶段需要停顿线程,但耗时很短,而且是借用进行Minor GC的时候同步完成的,所以G1 收集器在这个阶段实际并没有额外的停顿。
并发标记 (Concurrent Marking):从GC Root开始对堆中对象进行可达性分析,递归扫描 整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象 图扫描完成以后,还要重新处理SATB记录下的在并发时有引用变动的对象。
最终标记 (Final Marking):对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍 遗留下来的最后那少量的SATB记录。
筛选回收 (Live Data Counting and Evacuation):负责更新Region的统计数据,对各个 Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选 择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的 Region中,再清理掉整个旧Region的全部空间。这里的操作涉及存活对象的移动,是必须暂 停用户线程,由多条收集器线程并行完成的。
从上述阶段的描述可以看出,G1收集器除了并发标记外,其余阶段也是要完全暂停用户线程的 。