JVM 性能飞升秘籍:深入 CMS、G1、ZGC 核心世界

231 阅读5分钟

垃圾回收器分类与核心目标

垃圾回收器核心目标适用场景JDK版本支持
CMS低延迟(减少STW时间)中小堆内存、响应敏感型应用JDK8及之前(JDK14废弃)
G1平衡吞吐量与延迟(可预测停顿)中大堆内存(4GB~16GB)JDK9+(默认回收器)
ZGC极低延迟(亚毫秒级STW)超大堆内存(TB级)JDK11+(生产级支持JDK15+)


CMS(Concurrent Mark-Sweep)

1. 工作阶段

  • 初始标记(Initial Mark) :标记GC Roots直接关联的对象(STW,短暂停顿)。
  • 并发标记(Concurrent Mark) :遍历整个对象图(与用户线程并发)。
  • 重新标记(Remark) :修正并发标记期间变动的对象(STW,使用增量更新或原始快照)。
  • 并发清除(Concurrent Sweep) :清理垃圾对象(与用户线程并发)。

2. 核心特点

  • 优点:并发收集,减少STW时间。

  • 缺点

    • 内存碎片:长期运行后需Full GC压缩堆。
    • CPU敏感:并发阶段占用CPU资源,影响吞吐量。
    • 浮动垃圾:并发清除期间可能产生新垃圾。

3. 调优参数

-XX:+UseConcMarkSweepGC      # 启用CMS
-XX:CMSInitiatingOccupancyFraction=70  # 老年代使用率70%时触发CMS
-XX:+UseCMSCompactAtFullCollection   # Full GC时压缩内存

4. 常见问题

  • 并发模式失败(Concurrent Mode Failure)

    • 原因:CMS执行期间老年代空间不足。
    • 解决:增大老年代空间或降低触发阈值(CMSInitiatingOccupancyFraction)。
  • 内存碎片

    • 解决:定期Full GC或切换为G1/ZGC。

G1(Garbage-First)

1. 核心设计

  • Region分区:将堆划分为多个等大小(1MB~32MB)的Region,分为Eden、Survivor、Old、Humongous(存放大对象)。

  • Mixed GC:同时回收新生代和老年代Region。

  • 停顿预测模型:通过历史数据预测每次GC的停顿时间(默认目标200ms)。

    把堆分成若干个Region分区的作用是实现了更细粒度的内存管理,也就是所谓的分而治之的思想,同时G1也可以实现对单个Region进行回收,从而不需要对整个堆进行扫描和回收,这样大大提高了回收效率,当然,Region的价值大小(也就是说回收所获得的内存空间大小以及回收所需时间的经验值)会被G1跟踪并记录,在允许收集时间期间,会优先回收这种价值最大的Region,所以这也是G1的名字由来(Garbage First)

2. 工作阶段

  • 年轻代GC(Young GC) :回收Eden和Survivor区。
  • 并发标记(Concurrent Marking) :标记老年代存活对象(类似CMS)。
  • 混合回收(Mixed GC) :回收部分老年代Region(基于垃圾比例优先级)。

3. 调优参数

-XX:+UseG1GC                # 启用G1
-XX:MaxGCPauseMillis=200     # 目标停顿时间(毫秒)
-XX:G1HeapRegionSize=4m      # Region大小(需为2的幂)
-XX:InitiatingHeapOccupancyPercent=45  # 堆使用率45%时触发并发标记

4. 常见问题

  • 大对象分配失败

    • 原因:Humongous Region不足。
    • 解决:增大Region大小或减少大对象生成。
  • Mixed GC效率低

    • 解决:降低InitiatingHeapOccupancyPercent提前触发标记。

ZGC(Z Garbage Collector)

1. 核心设计

  • 染色指针(Colored Pointers) :在指针元数据中记录对象状态(可达性、重定位)。
  • 读屏障(Load Barrier) :在访问对象时触发屏障,处理对象重定位。
  • 无分代:全堆回收,但通过并发处理实现亚毫秒级STW。

1.1. 染色指针含义

染色指针是一种将标志位直接存储在对象指针中的技术。在 64 位系统中,指针的位数并没有被完全利用,ZGC 利用了这一点,将一些用于标记对象状态的标志位存储在指针的特定位上,就好像给指针染上了不同的 “颜色”,所以被称为染色指针。

1.1.1. 原理

在 64 位系统中,理论上可用的地址空间非常大,但实际上操作系统通常不会使用这么大的地址范围。以常见的情况为例,可能只会使用到其中 48 位来表示实际的内存地址,剩余的位就可以被 ZGC 用来存储额外的信息。 ZGC 的染色指针使用了其中的 4 位来存储 4 个标志信息,从低到高分别为:

  • Marked0:用于第一次标记阶段,标记对象是否被标记过。
  • Marked1:用于第二次标记阶段,和 Marked0 交替使用,避免重复初始化。
  • Remapped:用于重定位阶段,标记对象是否已经被移动到新的位置。
  • Finalizable:表示对象是否只能通过 finalizer 方法来访问。

2. 工作阶段

  • 并发标记(Concurrent Mark) :标记存活对象。
  • 并发预备重定位(Concurrent Prepare for Relocate) :确定重定位集。
  • 并发重定位(Concurrent Relocate) :移动对象并更新引用。
  • 引用处理(Reference Processing) :处理软/弱/虚引用。

3. 调优参数

-XX:+UseZGC                 # 启用ZGC
-XX:ZAllocationSpikeTolerance=5  # 内存分配尖峰容忍度(百分比)
-XX:ZCollectionInterval=120 # 强制GC间隔(秒,默认不限制)

4. 适用场景与限制

  • 优势:TB级堆内存、亚毫秒级停顿(<10ms)。
  • 限制:JDK15+生产级支持,Windows/macOS支持较晚。

三大回收器对比

维度CMSG1ZGC
STW时间中等(初始标记、重新标记)可控(基于预测模型)极低(亚毫秒级)
内存占用较高(Region元数据)高(染色指针、内存映射)
吞吐量中等
适用堆大小<4GB4GB~16GB>16GB(支持TB级)
内存碎片严重可控

场景选择建议

  1. 中小堆、低延迟:CMS(仅JDK8及之前)。
  2. 中大堆、平衡吞吐量与延迟:G1(JDK9+默认)。
  3. 超大堆、极致低延迟:ZGC(JDK15+生产环境)。

高频面试题

  1. CMS为什么被废弃?

    • 内存碎片问题难以解决,且G1/ZGC在吞吐量和延迟上更优。
  2. ZGC如何实现几乎无STW?

    • 通过染色指针和读屏障技术,将标记和重定位阶段并发执行。
  3. G1的Mixed GC如何选择Region?

    • 基于“垃圾优先”策略,优先回收垃圾比例高的Region。