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. 精细调阈值
相关推荐
m0_470857641 分钟前
Python如何构建异步消息队列_利用asyncio配合Redis实现任务分发
jvm·数据库·python
2301_781571421 分钟前
SQL嵌套子查询中的变量如何传递_作用域与上下文限制解析
jvm·数据库·python
m0_631529823 分钟前
Golang数组和切片有什么区别_Golang数组切片对比教程【通俗】
jvm·数据库·python
泓博4 分钟前
docker ubuntu源码安装openclaw的常见问题
java·linux·开发语言·ai
2401_880071404 分钟前
CSS如何利用Sass实现透明度动态化_通过函数计算CSS颜色值
jvm·数据库·python
iuvtsrt4 分钟前
如何进行SQL安全基线评估_定期核对数据库安全配置
jvm·数据库·python
Jetev5 分钟前
Python Tkinter自定义对话框怎么写_Toplevel创建子窗口并结合wait_window()实现阻塞
jvm·数据库·python
m0_591364735 分钟前
mysql如何配置缓存大小_mysql key_buffer_size基础设置
jvm·数据库·python
YuanDaima20485 分钟前
WSL2 核心中间件部署实战:MySQL、Redis 与 RocketMQ
java·数据库·人工智能·redis·python·mysql·rocketmq
南境十里·墨染春水6 分钟前
线程池学习(一) 理解 进程 线程 协程及上下文切换
java·开发语言·学习