JVM GC日志是最直接可信的内存行为记录源,需关注年轻代与老年代容量变化、回收量差值及时间维度波动模式,并通过结构化解析或JMX集成实现监控告警。

JVM GC 日志本身不是监控手段,而是最直接、最可信的内存行为记录源。它不依赖外部工具或网络采集,每行都真实反映某次 GC 前后各区域的容量、已用、回收量和时间点。要从中有效监控堆内存使用情况,关键是看对字段、盯住节奏、结合上下文判断异常。
看懂 GC 日志里的堆内存分布
日志中每次 GC(尤其是 -XX:+PrintGCDetails 启用后)都会输出类似这样的结构:
[GC (Allocation Failure) [PSYoungGen: 123456K->1234K(234560K)] 345678K->346789K(1048576K), 0.0456789 secs]
拆解关键字段含义:
-
PSYoungGen: A->B(C)→ 年轻代:GC前已用 A KB,GC后剩 B KB,总容量 C KB -
345678K->346789K(1048576K)→ 整个堆:GC前已用 345678 KB,GC后 346789 KB,总容量 1048576 KB(即 1G) - 若是 Full GC,还会单独列出
[ParOldGen: ...]或[G1 Old Gen: ...],对应老年代数据
重点关注三组差值:
- Eden 区释放量(
A - B)是否合理(如创建快但回收少,说明对象存活率高) - 老年代增量(
346789K - 345678K = +1111K)是否持续为正且变大 - 整堆使用量在 Minor GC 后是否明显回落;若回落极少(如只降 100KB),说明大量对象晋升
用时间维度识别健康波动模式
GC 日志带时间戳(加 -XX:+PrintGCDateStamps 或 -Xlog:gc*:time,uptime),可导出后绘制成折线图,观察以下典型模式:
- Eden 区应呈高频锯齿:每几秒上升 → Minor GC → 快速归零或降至低位
- 老年代应缓慢爬升 + 偶尔小幅下降:Full GC 后 OU 应回落 10%~30%,若从 850MB → 848MB,连续三次仅降 2MB,就是泄漏信号
- 单次 GC 耗时突增:比如平时 YGCT=12ms,突然跳到 85ms,可能 Survivor 溢出导致部分对象直送老年代
把日志变成可告警的监控指标
原始日志需结构化才能用于生产告警。推荐两种落地方式:
-
文本解析脚本(轻量级):用 Python 或 awk 提取每行的
PSYoungGen:和ParOldGen:数值,写入时序数据库(如 InfluxDB),再配置阈值告警(如“老年代 10 分钟内增长 >50MB”) -
集成 JMX Exporter(标准方案):启动时加
-Dcom.sun.management.jmxremote,用 Prometheus 抓取jvm_memory_used_bytes{area="heap",id="PS Old Gen"},Grafana 中叠加 GC 次数曲线,一眼看出“GC 频次升但老年代不降”的矛盾点
配合日志必须启用的基础参数
光有日志不够,得让它包含足够信息且不拖垮性能:
-
-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=5,filesize=50M(JDK 9+ 推荐) - 或 JDK 8 用
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=50M - 补充
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/oom/,OOM 时自动留证
不复杂但容易忽略











