JVM GC 日志分析 + 常见 GC 场景 + 实战参数调优

一、先搞懂:GC 日志到底看什么?(核心 4 个指标)

不管什么垃圾回收器,只盯这 4 个值:

  1. YGC 频率 & 耗时
    • 频率太高:Eden 太小 / 瞬时对象太多
    • 耗时太长:对象过大、晋升异常
  2. FGC 次数
    • 线上 FGC > 0 就属于风险
    • 一天多次 FGC = 必须立刻调优
  3. GC 总暂停时间(STW)
    • 单次 > 500ms 接口会超时
    • 累计占比 > 2% 系统不稳定
  4. 老年代增长速度
    • 匀速上涨:正常
    • 突刺上涨:内存泄漏 / 大对象 / 池化不当

二、开启 GC 日志(生产标准配置)

JDK8 + CMS

复制代码
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationStoppedTime
-Xloggc:/logs/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=100M

JDK11 + G1/ZGC

复制代码
-Xlog:gc*:/logs/gc.log:time,level,tags
-Xlog:gc+safepoint=trace

三、GC 日志关键字段解读(一眼定位问题)

1)Young GC 典型行

复制代码
2026-04-16T10:00:00.123+0800:
[GC (Allocation Failure)
[PSYoungGen: 102400K->2048K(153600K)]
122880K->22528K(524288K), 0.012 secs]
  • Allocation Failure:正常 YGC 原因
  • 102400K -> 2048K:年轻代回收前后
  • 0.012 secs:STW 耗时(<20ms 合格

2)Full GC 典型行

复制代码
[Full GC (System.gc())
[PSYoungGen: 0K->0K(153600K)]
[ParOldGen: 409600K->20480K(409600K)]
409600K->20480K(524288K),
[Metaspace: 12345K->12345K(1056768K)], 0.345 secs]
  • Full GC:危险信号
  • 0.345 secs:STW 345ms,接口必超时
  • 常见原因:
    • 老年代满
    • Metaspace 满
    • 代码里 System.gc()
    • 内存泄漏

四、最常用 GC 分析工具(直接用)

  1. GCeasy(在线,最强)
  2. GCViewer(本地)
  3. Arthas dashboard/gc
  4. jstat -gc 1000 10

最实用命令:

bash 复制代码
jstat -gc <pid> 1000 10

看:

  • YGC/YGCT
  • FGC/FGCT
  • OC/OU 老年代使用率

五、生产最常见 6 类 GC 问题 + 调优方案

1)YGC 太频繁(1秒多次)

现象

  • YGC 间隔 <1s
  • 单次耗时低,但总量高

原因

Eden 太小,对象一创建就满

调优

复制代码
-Xms4g -Xmx4g
-Xmn2g          # 加大年轻代
-XX:SurvivorRatio=8

2)YGC 耗时高(>50ms)

原因

  • 大对象频繁进入老年代
  • Survivor 太小,对象过早晋升

调优

复制代码
-XX:SurvivorRatio=6
-XX:InitialTenuringThreshold=10
-XX:MaxTenuringThreshold=15

3)老年代持续上涨 → 最终 FGC

90% 是内存泄漏

  • 线程池无界
  • HashMap/ThreadLocal 缓存不清理
  • 数据库连接未释放
  • 第三方包 bug

定位

复制代码
jmap -dump:format=b,file=dump.hprof <pid>
用 MAT 分析 GC Root

调优

修复代码,不是改 JVM 参数。


4)频繁 FullGC(最危险)

可能原因

  • 老年代空间不足
  • Metaspace 满
  • 内存泄漏
  • System.gc()

调优

复制代码
-XX:+DisableExplicitGC  # 禁止 System.gc()
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-Xmx加大

5) Mixed GC 频繁(G1)

原因

  • G1 堆太小
  • MixedGC 触发阈值不合理

调优

复制代码
-XX:+UseG1GC
-Xms4g -Xmx4g
-XX:G1HeapRegionSize=16m
-XX:InitiatingHeapOccupancyPercent=50  # 老年代50%开始混合回收
-XX:G1MixedGCCountTarget=8

6)接口超时毛刺 STW

解决方案

高并发微服务直接上 ZGC / Shenandoah

复制代码
-XX:+UseZGC
-Xms4g -Xmx4g

几乎 无 STW 毛刺


六、生产级 JVM 启动参数模板

模板1:JDK8 高并发微服务(ParNew + CMS)

复制代码
-Xms2g
-Xmx2g
-Xmn1g
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+DisableExplicitGC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/logs/gc.log

模板2:JDK17 微服务(G1,通用稳定)

复制代码
-Xms2g
-Xmx2g
-XX:+UseG1GC
-XX:G1HeapRegionSize=16m
-XX:MaxGCPauseMillis=20
-XX:+DisableExplicitGC
-Xlog:gc*:/logs/gc.log

模板3:超低延迟(支付/网关)ZGC

复制代码
-Xms4g
-Xmx4g
-XX:+UseZGC
-XX:+DisableExplicitGC

七、调优的真正顺序

  1. 看业务代码(内存泄漏、大对象、无界集合)→ 占70%问题
  2. 看对象生命周期
  3. 调整堆大小、年轻代大小
  4. 选择 GC 算法
  5. 精细调阈值
相关推荐
消失的旧时光-19432 小时前
Spring Boot 实战(五):接口工程化升级(统一返回 + 异常处理 + 错误码体系 + 异常流转机制)
java·spring boot·后端·解耦
2301_813599552 小时前
HTML图片怎么用UnoCSS对齐_UnoCSS原子化CSS图片对齐实战
jvm·数据库·python
m0_377618232 小时前
c++怎么在不加载整个大文件的情况下获取其SHA256校验值【进阶】
jvm·数据库·python
qq_189807032 小时前
CSS如何实现纯CSS树状目录结构_利用-checked与递归思维构建交互节点
jvm·数据库·python
2301_777599373 小时前
Go语言如何做HTTP连接池_Go语言HTTP连接池教程【最新】
jvm·数据库·python
Polar__Star3 小时前
Redis如何利用位图快速判断数据存在性
jvm·数据库·python
杨凯凡3 小时前
【012】图与最短路径:了解即可
java·数据结构
2301_817672263 小时前
CSS如何实现优雅的间距_使用CSS Grid控制盒模型间隙
jvm·数据库·python
Shorasul3 小时前
JavaScript中显式创建包装对象的后果与性能损耗
jvm·数据库·python