5.ZGC学习

#jvm #zgc #gc

1. CMS 和 G1 的痛点

CMS 和 G 1 都用标记-复制算法,GC 过程分三个阶段:

  1. STW 初始标记
  2. 并发标记
  3. STW 再标记 + STW 清理 + STW 复制

复制阶段需要把存活对象搬到新区域,这个阶段是 STW 的,停顿时间和存活对象的大小成正比。堆越大、存活对象越多,停顿越长,这是 G 1 在大堆场景下停顿时间难以控制的根本原因。G 1 的详细机制见 6.G1垃圾回收器

2. ZGC 怎么解决的?

ZGC 把复制阶段拆成"初始转移(STW,很短)+ 并发转移",让耗时的对象搬移在并发阶段完成,GC 线程和业务线程同时跑。

zgc并发回收

这样停顿时间就不再随堆大小增长,ZGC 的 STW 停顿通常在 1~10 ms 以内,即使是 TB 级别的堆也能保持低停顿。

3. 关键技术:着色指针 + 读屏障

并发转移有个问题:GC 线程在搬对象,业务线程也在访问对象,如果对象地址变了但业务线程还拿着旧地址,就会访问错误。

ZGC 用两个技术解决这个问题:

着色指针:在对象引用的地址里用几个 bit 标记对象的状态(是否被移动过)。

读屏障:业务线程每次读取对象引用时,JVM 插入一小段检查代码。如果发现对象已经被移动,自动把指针更新到新地址,业务线程始终访问的是最新地址。

这两个技术配合,让并发转移成为可能,代价是每次读对象引用都有极小的额外开销。读屏障的思路和 Java虚引用 的 Cleaner 机制有些相似,都是在对象访问路径上插入感知逻辑。

4. 什么时候用 ZGC?

JDK 21 开启分代 ZGC:

-XX:+UseZGC -XX:+ZGenerational

参考:美团 ZGC 实践