bigywater.tech
Java · 164

ZGC:几乎低停顿是怎么做到的

ZGC 为什么能做到几乎没有停顿?代价是什么?这篇用同一个程序在三种回收器、不同堆大小、不同存活集上量应用真正被打断的时间,再看 ZGC 一次回收的阶段(G1 的 Region 与停顿目标见前面的篇目,彩色指针在后面)。

260.54 / 88.6 / 0.49 ms
400 MB 存活集时 Parallel / G1 / ZGC(2g)的最长间隔
84 行
ZGC 堆缩到 1 GB 时日志里的 Allocation Stall 次数
3 次 Pause
一次 ZGC 回收里的停顿(Mark Start、Mark End、Relocate Start)

三个回收器的最长间隔

实测 · 本机执行输出
回收器                  存活集         日志里最长停顿(ms)           程序看到的最长间隔(ms)       >5 ms 的间隔次数      循环次数   日志里的 Allocation Stall 行
Parallel -Xmx2g   ≈40 MB               15.70                   15.78               114   1043026                         0
Parallel -Xmx2g  ≈400 MB              260.44                  260.54                52    205354                         0
G1 -Xmx2g         ≈40 MB                5.95                    6.01                18   1138758                         0
G1 -Xmx2g        ≈400 MB               84.17                   88.60                65    245734                         0
ZGC -Xmx1g        ≈40 MB                0.02                   17.47                40    836341                       121
ZGC -Xmx1g       ≈400 MB                0.01                   85.43                28    218739                        84
ZGC -Xmx2g        ≈40 MB                0.01                    0.63                 0    913754                         0
ZGC -Xmx2g       ≈400 MB                0.01                    0.49                 0    275185                         0
ZGC -Xmx4g        ≈40 MB                0.01                    1.10                 0    892858                         0
ZGC -Xmx4g       ≈400 MB                0.01                    0.63                 0    272257                         0

ZGC 的阶段

实测 · 本机执行输出
  Pause Mark Start 0.003ms
  Concurrent Mark 96.250ms
  Pause Mark End 0.007ms
  Concurrent Mark Free 0.000ms
  Concurrent Process Non-Strong References 0.148ms
  Concurrent Reset Relocation Set 0.008ms
  Concurrent Select Relocation Set 2.479ms
  Pause Relocate Start 0.003ms
  Concurrent Relocate 30.033ms

分步演示

ZGC
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,ZGC 是非分代模式(-XX:+UseZGC);程序是自写的分配循环,每组运行 6 秒
    • 没有验证:分代 ZGC(-XX:+ZGenerational 与 JDK 27 的默认分代)、大页与 NUMA、吞吐对比、更大的堆(几十 GB)、软限制 SoftMaxHeapSize、标记并发线程数(ConcGCThreads)的调整;所有数字来自一次运行
    京ICP备2026067502号-1京公网安备11010502063487号