要记录gc前后的内存变化,必须同时启用-xx:+printgcdetails、-xx:+printheapatgc和-xloggc:/path/to/gc.log(jdk 8)或-xlog:gc,heap,age*:file=...(jdk 11+),辅以时间戳和年龄分布参数以提升可读性与分析精度。

要记录 GC 前后的内存变化,关键在于启用能显示堆各区域(Eden、Survivor、Old、Metaspace)在每次 GC 前后详细占用情况的日志参数。仅用 -XX:+PrintGC 是不够的,它只输出简略信息;必须加上能展开内存分布的选项。
必须启用的核心参数
以下三个参数需同时配置,缺一不可:
-
-XX:+PrintGCDetails:输出分代内存结构(如 PSYoungGen、ParOldGen)、各区域回收前后的大小及总容量,是分析内存变化的基础。 -
-XX:+PrintHeapAtGC:在每次 GC 前后分别打印完整堆快照,包括各代实际使用量、已提交容量、Region 分布(G1/ZGC 下也适用),比PrintGCDetails更细粒度。 -
-Xloggc:/path/to/gc.log(JDK 8)或-Xlog:gc*,heap*:file=...(JDK 11+):将日志持久化到文件,确保可回溯分析;路径需有写权限,建议用绝对路径。
增强可读性与定位效率的辅助参数
光有内存数据还不够,时间线和上下文很重要:
-
-XX:+PrintGCDateStamps或-XX:+PrintGCTimeStamps:添加时间戳,便于关联业务请求或监控图表。推荐优先用DateStamps,避免启动偏移带来的换算误差。 -
-XX:+PrintTenuringDistribution(JDK 8/9):显示 Survivor 中对象年龄分布,帮助判断晋升是否异常——若每次 GC 后 “age 1” 对象大量堆积,可能 Survivor 空间不足或对象存活周期长。 -
-Xlog:gc+heap+age(JDK 11+):替代旧参数,一条指令覆盖堆变化与年龄信息,更简洁可靠。
不同 JDK 版本的典型配置示例
JDK 8 及以下:-Xloggc:/var/log/app/gc.log -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
JDK 11 及以上(推荐):-Xlog:gc*,heap*,age*:file=/var/log/app/gc.log:time,uptime,level,tags:filecount=10,filesize=100M
注意:gc* 包含所有 GC 事件,heap* 确保输出各代内存快照,age 补充晋升行为,filecount 和 filesize 防止日志撑爆磁盘。
验证日志是否生效
启动后触发一次 GC(例如调用 System.gc() 或制造 Minor GC),查看日志中是否出现类似内容:
- 含
[PSYoungGen: 12345K->678K(15360K)]的分代回收行(来自PrintGCDetails) - 含
Heap before GC invocations=5 (full 0):和Heap after GC invocations=5 (full 0):的完整堆段(来自PrintHeapAtGC) - 含
Desired survivor size 1048576 bytes, new threshold 7 (max 15)的年龄分布(来自PrintTenuringDistribution)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










