导航
一. G1垃圾收集算法详解
G1
(Garbage-First)是一款面向服务器
的垃圾收集器,主要针对配备多个处理器及大容量内存的机器,以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。
- 使用G1,JVM堆中不存在物理划分的年轻代,S0,S1区和老年代区,但是保存了年轻代和老年代的概念,并且引用了`大对象区域Humongous
- G1将JVM堆内存分成大小相等的
独立区域(Region),
JVM最多可以有2048
个Region - 一个Region的大小等于堆大小除以2048,假如堆内存是4096M,那么一个Region的大小就是2M,也可以使用参数“-XX:G1HeapRegionSize”手动指定Region大小,但是建议使用默认大小
- 默认
年轻代
占堆内存的大小是5%
,如果堆大小为4096M,那么年轻代占200M的内存大小,对应大概100个Region大小,可以通过“-XX:G1NewSizePercent”设置新生代的初始占比,在系统运行中,JVM会不断的给年轻代增加更多的Region,但是上限是不能超过堆大小的60%,可以通过 “-XX:G1MaxNewSizePercent”调整。 年轻代
中的Eden和Survivor对应的region也跟之前一样,默认8:1:1,假设年轻代现在有1000个Region,Eden区对应800个,S0对应100个,S1对应100个。- 一个Region可能之前是年轻代,如果Region进行了垃圾回收,之后可能又会变成老年代,也就是说Region的区域功能可能会动态变化。
1. 大对象Humongous说明
G1专门分配大对象的区域称为“Humongous区”,而不是让大对象直接进入老年代区域。对大对象的定义是:当一个对象的大小超过了Region大小的50%,比如一个Region大小是2M,那么一个对象的大小超过1M就会放到Humongous区中,如果一个对象是6M大小,那么占位3个连续的Region区域。
Humongous区只是暂时短暂的存放大对象,不直接进入老年代,可以节约老年代的空间,避免老年代的空间内存不足而产生的GC开销。
Full GC 不仅会收集年轻代和老年代的区域, Humongous区也会一并回收。
2. G1收集器执行一次GC运行的过程步骤
- 初始标记(Initial Mark STW): 暂停所有其他线程,并记录GC Roots直接引用的对象,速度很快
- 并发标记(Concurrent Marking):就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行。因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变。(同CMS并发标记步骤一致)
- 最终标记(Remark STW):就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短。主要用到三色标记里的增量更新算法做重新标记。(同CMS重新标记步骤一致)
- 筛选回收(Cleanup STW):首先对各个Region的回收价值和成本进行排序,根据用户所希望的GC停顿时间(可以用JVM参数“-XX:MaxGCPauseMillis”指定)来制定回收计划