ZGC 执行日志:解锁低延迟运行的核心密码

ZGC 的执行日志可以通过 JVM 参数配置输出,包含垃圾回收的阶段、时间、堆内存变化等关键信息,是分析 ZGC 运行状态、调优性能的重要依据。以下是 ZGC 日志的配置方式、关键内容解读及示例分析:

一、启用 ZGC 日志的核心参数

通过 -Xlog 系列参数控制 ZGC 日志的输出(JDK 9+ 统一日志框架),常用配置如下:

参数示例 说明
-XX:+ZPrintGC 基础日志:输出 GC 触发、阶段、耗时等关键信息(简洁版)
-XX:+ZPrintGCDetails 详细日志:包含堆区域变化、指针颜色调整、线程参与等细节
-Xlog:gc*:file=zgc.log:time,level,tags 输出到文件:将 GC 相关日志(gc*)写入 zgc.log,包含时间、级别、标签
-Xlog:gc=debug:file=zgc-debug.log 调试级日志:输出更细粒度的阶段执行细节(适合深度分析)

二、ZGC 日志的核心内容解读

ZGC 的日志按 回收周期 划分,每个周期包含多个阶段,关键信息如下:

1. 日志开头:GC 触发原因与堆状态

log 复制代码
[0.834s][info][gc] ZGC(0) Initial Mark Start (size 256M)  
  • ZGC(0):第 0 次 ZGC 回收(从 0 开始计数)。
  • Initial Mark Start:开始初始标记阶段。
  • size 256M:当前堆大小为 256MB。
  • 触发原因可能包括:Allocation Rate(内存分配速率过高)、Heap Exhausted(堆即将耗尽)等。

2. 核心阶段日志(按执行顺序)

(1)初始标记(Initial Mark)------ STW 阶段
log 复制代码
[0.835s][info][gc] ZGC(0) Initial Mark End (1.2ms)  
  • End (1.2ms):初始标记结束,耗时 1.2ms(STW 时间,极短)。
  • 作用:标记根对象(线程栈、静态变量等),为后续并发标记奠定基础。
(2)并发标记(Concurrent Mark)
log 复制代码
[0.835s][info][gc] ZGC(0) Concurrent Mark Start  
[0.842s][info][gc] ZGC(0) Concurrent Mark End (7.3ms)  
  • 全程并发执行(与应用线程同时运行),耗时 7.3ms。
  • 作用:遍历对象图,标记所有存活对象(通过着色指针标记状态)。
(3)最终标记(Final Mark)------ STW 阶段
log 复制代码
[0.842s][info][gc] ZGC(0) Final Mark Start  
[0.842s][info][gc] ZGC(0) Final Mark End (0.3ms)  
  • STW 时间 0.3ms,处理并发标记中遗漏的对象(如并发标记期间新产生的根对象)。
(4)并发预备转移(Concurrent Prepare for Relocation)
log 复制代码
[0.842s][info][gc] ZGC(0) Concurrent Prepare for Relocation Start  
[0.843s][info][gc] ZGC(0) Concurrent Prepare for Relocation End (0.9ms)  
  • 并发执行,准备需要转移的 Region(筛选出内存碎片多、存活对象少的 Region)。
(5)初始转移(Initial Relocate)------ STW 阶段
log 复制代码
[0.843s][info][gc] ZGC(0) Initial Relocate Start  
[0.843s][info][gc] ZGC(0) Initial Relocate End (0.2ms)  
  • 极短 STW(0.2ms),转移根对象直接引用的对象(为并发转移铺路)。
(6)并发转移(Concurrent Relocate)
log 复制代码
[0.843s][info][gc] ZGC(0) Concurrent Relocate Start  
[0.851s][info][gc] ZGC(0) Concurrent Relocate End (8.1ms)  
  • 并发执行,将存活对象从旧 Region 转移到新 Region(压缩内存,避免碎片),通过着色指针和读屏障保证应用线程访问正确地址。
(7)并发清理(Concurrent Cleanup)
log 复制代码
[0.851s][info][gc] ZGC(0) Concurrent Cleanup Start  
[0.852s][info][gc] ZGC(0) Concurrent Cleanup End (0.5ms)  
  • 并发回收空 Region(已完成对象转移的旧 Region),释放内存供下次分配。

3. 周期总结:总耗时与堆变化

log 复制代码
[0.852s][info][gc] ZGC(0) Heap After GC: 128M used, 384M capacity (1.5s)  
  • Heap After GC:GC 后堆使用量 128MB,总容量 384MB。
  • 整个 GC 周期耗时 1.5s(主要是并发阶段,STW 总耗时仅 ~2ms)。

三、关键指标与分析重点

  1. STW 时间 :关注 Initial MarkFinal MarkInitial Relocate 三个阶段的耗时,正常应 <10ms,若超标可能需调优堆大小或 GC 线程数。
  2. GC 频率 :短时间内频繁触发 GC(如每秒多次),可能是内存分配速率过高或堆过小,需增大堆(-Xmx)或优化对象创建。
  3. 堆使用率Heap After GC 的使用率若持续超过 70%,可能导致 GC 频繁,建议调整堆大小或 ZMaxHeapSizePercent(默认 90%)。
  4. 转移效率Concurrent Relocate 耗时过长,可能是存活对象过多(需优化对象生命周期)或 CPU 资源不足(增加 GC 线程:-XX:ZGCThreads=n)。

四、实战示例:通过日志定位问题

若日志中频繁出现:

log 复制代码
[5.210s][warn][gc] ZGC(10) Heap exhausted, starting GC immediately  

说明堆内存即将耗尽,GC 被迫紧急触发,可能原因:

  • 堆大小不足(需增大 -Xmx);
  • 存在内存泄漏(需结合内存快照分析大对象)。

通过配置 ZGC 日志并聚焦上述关键信息,可有效评估其低延迟特性、定位性能瓶颈,为调优提供数据支撑。

相关推荐
Java中文社群6 分钟前
快看!百度提前批的面试难度,你能拿下吗?
java·后端·面试
小高0072 小时前
🚀Promise 全家桶:原理、实现、API、实战,一篇搞定
前端·javascript·面试
MrSkye2 小时前
🔥披萨还没到你就吃了?”JavaScript异步编程入门全解🔥
前端·javascript·面试
北京_宏哥3 小时前
🔥《刚刚问世》系列初窥篇-Java+Playwright自动化测试-32- 操作日历时间控件-下篇(详细教程)
java·前端·面试
拾光拾趣录5 小时前
🔥FormData+Ajax组合拳,居然现在还用这种原始方式?💥
前端·面试
拾光拾趣录6 小时前
🔥9种继承写法全解,第7种99%人没用过?⚠️
前端·面试
Monika Zhang6 小时前
【面试攻略】回答Java面试问题「挑战与解决方案」技巧
面试·职场和发展
我是哪吒6 小时前
分布式微服务系统架构第160集:百万台设备Netty网关架构
后端·面试·github
UrbanJazzerati6 小时前
如何安全地将本地分支与远程分支完全同步?为什么用 git fetch 而不是 git pull?
面试