JVM-垃圾回收(3)
垃圾回收器补充——G1(Garbage First)
G1垃圾回收器在2012年JDK 7u4中得到官方支持
而在2017年的JDK9更是将其设定为默认的垃圾回收器
G1的特点很多:
- 同时注重吞吐量(Throughput)和低延迟(Low Latency),默认的暂停目标是200ms
- 适用超大的堆内存,会将堆划分为多个大小相等的区域Region
- 整体采用标记-整理算法,而两个区域Region之间采用复制算法
相关的JVM参数:
-XX:UseG1GC
-XX:G1HeapRegionSize=size
-XX:MaxGCPauseMillis=time
解释:
- 启动G1
- 设置区域的大小
- 设置暂停目标
G1的垃圾回收过程
1. G1的堆结构和堆分配
G1的堆结构分为许多固定大小的区域,这些区域被映射到伊甸园、幸存区和老年代的逻辑表示中。

就以上面的图片为例,绿色的是伊甸区,黄色的是幸存区,蓝色的是老年代
值得注意的是,这些区域不需要像之前的的垃圾收集器那样相连。
此外,还有第四种类型的区域被称为Humongous区域。这些区域被设计用来容纳大小为标准区域50%或更大的对象。
2. G1中的Young GC
存活的对象被疏散(即复制或移动)到一个或多个幸存者区域。如果达到衰老阈值,一些对象将推广到老年代区域。
G1中的Young GC同样会触发STW


最近进入幸存区域的对象用深绿色表示,最近进入老年区域的用深蓝色表示。
总结:
- 堆是分割成区域的单个内存空间。
- 年轻代内存由一组不连续的区域组成。这使得在需要时可以很容易地调整大小。
- 年轻代垃圾收集或Young GC是STW事件。所有应用程序线程都将为此操作停止。
- Young GC使用多个线程并行完成。
- 活动对象被复制到新的幸存区或老年代区域。
3. G1中的Old GC阶段
| 阶段 | 描述 |
|---|---|
| (1)初始标记 (STW事件) | 这是一个STW事件。对于G1,初始标记承载在Young GC上。标记幸存者区域(根区域),可能老年代中有对象引用这些区域。 |
| (2)根区域扫描 | 扫描幸存者区域以查找老年代中的引用。这是在应用程序继续运行时发生的。这个阶段必须在Young GC发生之前完成。 |
| (3)并行标记 | 在整个堆上查找活跃对象。这发生在应用程序运行时。此阶段可被年轻代垃圾收集中断。 |
| (4)再标记 (STW事件) | 完成堆中活动对象的标记。使用一种称为snapshot-at-the-beginning(SATB)的算法,它比CMS收集器中使用的算法快得多。 |
| (5)清除 (STW事件和并发) | 对活动对象和完全自由的区域执行计算(STW);清除(STW);重置空区域并将它们返回到空闲列表(并发) |
| (*)复制 (STW事件) | 疏散或者复制存活的对象到新的未使用的区域 |
活动对象的初始标记由年轻代垃圾收集承载。在日志中,这被记录为GC pause (young)(inital-mark)
如果发现空区域(如“X”所示),则会在Remark阶段立即删除它们。

空区域被移除并回收,现在要计算所有区域活跃信息。
G1选择“活跃信息”最低的区域,即收集起来速度最快的区域。然后,这些区域与Young GC同时被收集。这在日志中表示为[GC pause (mixed)]。所以年轻一代和年老一代同时被收集。

所选区域已被收集并压缩为图中所示的深蓝区域和深绿色区域。

总结:
- 并发标记阶段
- 活跃信息是在应用程序运行时并发计算的。
- 这个活跃信息确定了在疏散暂停期间哪些区域最好回收。
- 没有像CMS那样的sweeping清扫阶段。
- 再标记阶段
- 使用Snapshot-the-Beginning(SATB)算法,该算法比CMS使用的要快得多。
- 完全空的区域被回收。
- 复制/清理阶段
- 年轻代和老年代同时被回收。
- 老年代区域是根据它们的活跃度来选择的。
浙公网安备 33010602011771号