ZGC(Z Garbage Collector)是 JDK 11 引入的一款低延迟垃圾回收器,主要目标是将 GC 停顿时间控制在 10ms 以内,并且能在超大堆内存(TB 级别)下保持可预测的低延迟表现。
1. ZGC 的特点
- 低延迟:GC 暂停时间通常不超过 1~2ms,不随堆大小增长而增加。
- 可扩展性强:支持从 数百 MB 到 16TB 的堆大小。
- 并发回收:大多数垃圾回收工作与应用线程并发进行。
- 着色指针(Colored Pointers):利用 64 位地址空间中的未使用位来存储对象的 GC 状态标记,从而减少额外的内存访问和同步开销。
- Region 化堆:将堆划分为大小不一的 Region,类似 G1,但 Region 更灵活(动态大小,2MB–16GB)。
2. ZGC 的回收过程
ZGC 的垃圾回收分为几个主要阶段:
- 初始标记 (Pause)
- 短暂停顿,标记 GC Roots 直接可达的对象。
- 并发标记 (Concurrent Marking)
- 和应用线程并发,遍历对象图,标记可达对象。
- 并发重定位 (Concurrent Relocation)
- 将存活对象从旧 Region 移动到新 Region,避免碎片化。
- 使用 读屏障 (Load Barrier) 保证应用访问对象时能找到新位置。
- 并发清理 (Concurrent Reset / Remap)
- 释放无用的 Region,整理元数据。
3. ZGC 的优势场景
- 超大堆:例如 100GB ~ TB 级别内存的应用(如大数据、AI 训练平台)。
- 低延迟系统:金融交易、广告投放、在线游戏、高并发 Web 服务。
- 需要高吞吐和稳定响应的应用。
4. 使用方式
在启动 Java 程序时添加参数即可启用 ZGC:
java -XX:+UseZGC -Xmx16g -Xms16g -jar app.jar
常见参数:
-XX:+UseZGC
启用 ZGC。-Xmx
、-Xms
设置堆大小。-XX:ZUncommitDelay=300
设置释放未使用内存的延迟(默认 5 分钟)。
5. 与其他 GC 的对比
GC 类型 | 停顿时间 | 吞吐量 | 最大堆支持 | 适用场景 |
---|---|---|---|---|
Serial | 高 | 一般 | 小堆 | 单核、小应用 |
Parallel | 高 | 高 | 大堆 | 批处理、吞吐优先 |
CMS | 中 | 一般 | 几百 GB | 延迟敏感但对碎片化敏感 |
G1 | 中低 | 高 | 数 TB | 通用低延迟 |
ZGC | 极低 | 高 | 16TB | 超大堆、低延迟应用 |
Shenandoah | 极低 | 一般 | 数 TB | Red Hat 提供,低延迟场景 |
加上代码(启动参数 + 示例程序 + 监控/调试命令)
下面把常用的 ZGC 启动参数、GC 日志配置示例、一个简单的 压力测试 Java 程序(用于观察 ZGC 行为)以及常用的 监控 / 调试命令 都贴出来,方便你直接复制运行并观察效果。
1. 启动 JVM 的常用示例
推荐(JDK9+ 的 unified logging):
# 在生产/测试机器上启动应用(示例:16GB 堆)
java -XX:+UseZGC \
-Xms16g -Xmx16g \
-XX:ZUncommitDelay=300 \
-Xlog:gc*:file=./logs/gc.log:time,uptimemillis,level,tags \
-jar your-app.jar
如果你使用的是较老风格的 GC 日志(非必需,仅供参考):
java -XX:+UseZGC -Xms16g -Xmx16g \
-Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps \
-jar your-app.jar
参数说明(简短):
-XX:+UseZGC
:启用 ZGC。-Xms
/-Xmx
:最小/最大堆。-XX:ZUncommitDelay=300
:空闲 region 释放回操作系统的延迟(秒)。-Xlog:gc*:file=...:time,uptimemillis,level,tags
:统一 GC 日志到文件并记录时间戳和标签。
2. 简单的压力测试 Java 程序(用于观察 ZGC 行为)
这个程序会不断分配中等大小的 byte[],并周期性打印内存占用,方便你在 GC 日志/监控工具下观察 ZGC 的并发回收与停顿。
// 文件名: ZGCStress.java
public class ZGCStress {
public static void main(String[] args) throws InterruptedException {
System.out.println("Starting ZGC stress test");
Runtime rt = Runtime.getRuntime();
java.util.List<byte[]> list = new java.util.ArrayList<>();
int iter = 0;
while (true) {
// 每轮分配 100 个 1MB 的对象(可调整)
for (int i = 0; i < 100; i++) {
list.add(new byte[1024 * 1024]); // 1MB
}
// 控制 list 大小,避免 OOM:保留最近 N 批
if (list.size() > 5000) { // 大约 5GB
// 丢弃前面的一些引用,让它们成为垃圾
for (int i = 0; i < 1000; i++) {
list.set(i, null);
}
// 轻微整理
java.util.Iterator<byte[]> it = list.iterator();
java.util.List<byte[]> newList = new java.util.ArrayList<>();
while (it.hasNext()) {
byte[] b = it.next();
if (b != null) newList.add(b);
}
list = newList;
}
// 每 5 秒打印一次内存状态
if (++iter % 2 == 0) {
long total = rt.totalMemory();
long free = rt.freeMemory();
long used = total - free;
System.out.printf("[%s] Used: %.2f MB, Total: %.2f MB, Free: %.2f MB%n",
java.time.LocalTime.now(),
used / 1024.0 / 1024.0,
total / 1024.0 / 1024.0,
free / 1024.0 / 1024.0);
}
Thread.sleep(2500); // 每轮间隔
}
}
}
编译并运行(示例):
javac ZGCStress.java
# 使用 ZGC 启动(示例 8GB 堆)
java -XX:+UseZGC -Xms8g -Xmx8g -Xlog:gc*:file=gc.log:time,uptimemillis,level,tags ZGCStress
观察:运行若干分钟后,打开 gc.log
,并用 jstat
/jcmd
等工具查看堆/GC 活动。
3. 常用的 JVM 运行时监控与调试命令
假设你已经获得目标 JVM 的 PID(用 jps
/ ps
找到):
- 列出 JVM 进程:
jps -l
- 触发一次显式 GC(让 GC 立刻执行):
jcmd <pid> GC.run
- 获取堆直方图(类实例统计):
jcmd <pid> GC.class_histogram
- 查看堆摘要(类似 jmap -heap):
jcmd <pid> GC.heap_info
# 或
jmap -heap <pid>
- 实时监控(每秒)GC/堆信息:
jstat -gc <pid> 1000
- 使用 VisualVM / Java Mission Control(JMC)连接观察 ZGC 的行为、线程、堆、延迟分布图(推荐用于 GUI 可视化)。
4. 常见调优点与注意事项(代码/参数相关)
- 日志级别:使用
-Xlog:gc*
保存详细日志以便离线分析;线上谨慎开启高频日志以免 I/O 影响性能。 - 小堆 & ZGC:ZGC 优势在超大堆与低延迟场景。对于小堆(几百 MB)不一定是最优选择。
- 保持最新 JDK:ZGC 在较新 JDK(11+, 17+, 19+)上逐步改进,生产时尽量使用你平台支持的稳定版本。
ZUncommitDelay
:控制从 OS 释放未使用内存的延迟(单位秒),可以根据内存波动调整。
5. 示例:结合 Systemd 启动脚本(可选)
如果你要在系统服务中启动,示例 systemd unit(片段):
[Unit]
Description=MyApp with ZGC
[Service]
User=app
ExecStart=/usr/bin/java -XX:+UseZGC -Xms16g -Xmx16g -XX:ZUncommitDelay=300 -Xlog:gc*:file=/var/log/myapp/gc.log:time,uptimemillis,level,tags -jar /opt/myapp/app.jar
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
发表回复