JDK 8及以前用-Xloggc等传统参数,JDK 9+推荐-Xlog统一日志;均需指定路径、启用详情与时间戳,生产环境须配置滚动策略;可动态通过jcmd开启。

开启 JVM GC 日志并输出到文件,核心是添加正确的启动参数,关键取决于你使用的 JDK 版本。JDK 8 及以前用传统参数组合,JDK 9 及以后推荐统一使用 -Xlog,更简洁、功能更强。
JDK 8 及之前:传统参数方式
这是最广泛兼容的方式,适用于大多数老项目和稳定环境:
-
-Xloggc:/path/to/gc.log:指定日志写入的绝对路径文件(如
/var/log/myapp/gc.log),确保 JVM 进程对该路径有写权限; - -XX:+PrintGCDetails:必加项,输出每次 GC 的详细信息(分代内存变化、回收前后大小、GC 类型等);
-
-XX:+PrintGCDateStamps:带完整日期时间(如
2026-10-14T02:19:30.123+0800),利于跨时区或长时间分析; - -XX:+PrintGCTimeStamps:可选,补充 JVM 启动后经过的秒级时间戳,适合看 GC 频率节奏;
- -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=100M:生产环境强烈建议加上,防止日志撑爆磁盘。
示例启动命令:java -Xloggc:/opt/app/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=100M -jar app.jar
JDK 9 及之后:统一日志框架(-Xlog)
语法更规范,支持标签过滤、多输出目标和精细控制,是当前推荐方式:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- -Xlog:gc*:file=/path/to/gc.log:time,level,tags:filecount=5,filesize=100M:一行搞定全部常用需求;
-
gc*表示启用所有 GC 相关子系统日志(包括gc+heap、gc+age、gc+metaspace等); -
time,level,tags控制日志格式,含毫秒级时间戳、INFO/WARN 级别、以及 gc/cms/zgc 等执行器标签; - 滚动策略直接内建,无需额外参数。
示例启动命令:java -Xlog:gc*:file=/opt/app/logs/gc.log:time,level,tags:filecount=5,filesize=100M -jar app.jar
运行时动态开启(不重启应用)
适用于线上紧急排查,无需修改启动参数或重启服务:
- 使用
jcmd工具(JDK 7u40+ 内置):jcmd <pid> VM.log output=gc what=gc→ 输出到控制台jcmd <pid> VM.log output=/tmp/runtime-gc.log what=gc→ 输出到文件 - 也可通过 JMX 或 Java 代码调用
DiagnosticCommandMBean.vmLog实现编程式启用; - 注意:动态开启的日志默认不继承启动时的滚动配置,需手动管理文件生命周期。
验证是否生效
启动后检查两件事:
- 确认日志文件已创建且有内容(哪怕只有一行时间戳);
- 触发一次 GC(例如在测试环境调用
System.gc(),或制造内存分配压力),观察日志是否追加新记录; - 若无输出,检查路径权限、JVM 版本是否匹配参数(如 JDK 11 用
-XX:+PrintGCDetails会静默忽略)。

















