-xlog:gc 是 jdk 9+ 替代 -xx:+printgcdetails 的标准做法,支持可控、可过滤、可重定向的 gc 日志,需显式指定输出路径与时间精度标签,生产环境推荐配置为 -xlog:gc:file=/data/logs/gc.log:time,uptime,level,tags:filecount=32,filesize=64m。

用 -Xlog:gc* 替代 -XX:+PrintGCDetails 是当前 JDK 9+ 的标准做法
Java 9 起,-XX:+PrintGCDetails 已被标记为废弃(deprecated),JDK 10+ 默认不可用;继续用它会触发警告,且日志格式混乱、字段缺失、无法定向输出。真正可控、可过滤、可重定向的 GC 日志能力,来自统一的日志系统 -Xlog。
-
-Xlog:gc开启基础 GC 日志,等价于旧版-XX:+PrintGC -
-Xlog:gc*启用所有 GC 相关子系统(如gc+heap、gc+metaspace),信息最全,适合分析 Full GC 原因或内存泄漏 - 必须显式指定输出目标,否则默认打到 stdout —— 生产环境务必加
:file=/path/gc.log,否则容易丢日志 - 时间戳默认不带毫秒级精度,需加
:time,uptime,tid,level才能对齐应用线程栈或监控指标
-Xlog 的输出格式和关键标签影响日志可读性
默认格式太简略,比如只显示 [0.123s][info][gc] GC(0) Pause Young (Normal) ...,看不出 Eden/Survivor 使用率、晋升量、元空间变化。得靠标签补全:
-
gc+heap=debug:显示每次 GC 前后各代内存占用(单位 KB)、已用/最大值,是判断内存分配速率和 Survivor 空间是否够用的核心依据 -
gc+metaspace=debug:暴露元空间回收行为,避免把java.lang.OutOfMemoryError: Metaspace误判为堆问题 -
gc+age=trace:显示对象年龄分布,能快速识别是否发生过早晋升(比如 age 1 就进老年代) - 别滥用
all=debug—— 日志量爆炸,I/O 拖慢 JVM,尤其高并发场景下可能引发 STW 延长
常见错误:日志没生成 / 内容为空 / 时间错乱
不是配置写错了,而是三个隐蔽点没处理好:
- 路径权限不足:
file=/var/log/app/gc.log但 JVM 进程用户无/var/log/app/写权限 → 日志静默失败,连 warning 都不报 - 文件被外部轮转工具(如 logrotate)删掉但 JVM 持有旧 fd → 新日志写不进磁盘,看起来像“没生成”,实际在内核 buffer 里丢弃了
- JVM 启动时系统时间跳变(如 NTP 校准或虚拟机休眠唤醒)→
uptime和time标签出现负数或断层,导致时序分析失真 - OpenJDK 与 Oracle JDK 在
gc+phases标签下行为不一致:前者部分 phase 名称不同(如gc+phases=debug在 Oracle JDK 中叫gc+phases=trace),跨版本迁移时需验证
生产环境推荐的一行可用配置
兼顾信息量、性能开销和落地稳定性:
立即学习“Java免费学习笔记(深入)”;
-Xlog:gc*:file=/data/logs/gc.log:time,uptime,level,tags:filecount=32,filesize=64m
-
gc*覆盖主流 GC 事件,不含冗余子系统(如gc+stringdedup) -
filecount=32,filesize=64m启用自动滚动,避免单文件过大难打开;注意:该功能仅 JDK 10+ 支持,JDK 8/9 必须用外部脚本轮转 - 不加
stdout或stderr,防止日志混入应用日志流,干扰grep或 ELK 解析 - 如果用 G1,建议额外加
gc+ergo=debug查看自适应调优决策(如 Mixed GC 触发阈值变化)
GC 日志本身不解决性能问题,但它是最接近真相的原始证据——参数配错、路径失效、时间漂移,任何一个细节没对齐,后面所有分析都可能是错的。








