news 2026/4/18 10:44:15

# JVM GC调优三板斧——先诊断、再调参、后验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
# JVM GC调优三板斧——先诊断、再调参、后验证

JVM GC调优三板斧——先诊断、再调参、后验证

背景

政务系统上线后,运维反馈系统偶尔会"卡一下",持续时间不长,但频率不固定。数据库慢SQL排查过了,网络也没问题,服务器资源充足。

这种"说不清道不明"的性能问题,最后往往落在JVM的GC上。

2023年处理过一个类似问题,总结了一套三板斧流程:先用jstat诊断GC原因,再针对性调参,最后验证效果

第一步:诊断——jstat -gccause 看清GC的"病历"

很多人知道用jstat -gcutil看GC统计,但-gcutil只告诉你频率和耗时,不告诉你为什么触发GC。

真正好用的命令是:

jstat-gccause<pid>1000

每秒输出一次GC统计,最后两列是关键:

S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC 0.00 0.00 68.23 45.67 92.13 88.45 234 2.345 5 6.789 9.134 Allocation Failure No GC 0.00 0.00 12.34 46.12 92.13 88.45 235 2.378 5 6.789 9.167 Allocation Failure No GC 0.00 0.00 78.90 46.89 92.13 88.45 236 2.412 6 8.234 10.646 Allocation Failure Full GC (Metadata GC Threshold)

重点看最后两列:

含义怎么读
LGCC上一次GC的原因最近一次GC为什么触发
GCC当前GC的原因现在正在进行的GC为什么触发(No GC表示空闲)

常见GC原因对照:

LGCC/GCC的值含义怎么办
Allocation Failure新生代分配失败,正常YGC频率太高就调大新生代
Full GC (Metadata GC Threshold)Metaspace满了调大Metaspace
Full GC (System.gc())代码显式调了System.gc()加-XX:+DisableExplicitGC
Full GC (Ergonomics)JDK自适应触发看老年代使用率,可能堆太小
Full GC (Heap Dump Initiated GC)做了heap dump排查dump的来源
Full GC (Last ditch collection)CMS/G1老年代回收失败兜底严重了,堆内存根本不够用

盯了几分钟,如果发现Full GC频繁且原因明确(比如Metaspace不够),调参就有了方向。

第二步:调参——对症下药

诊断出原因后,针对性调整JVM参数。不要上来就抄网上的"JVM调优最佳实践"——不同系统的GC特征不一样,参数也不一样。

场景一:Allocation Failure过于频繁

说明新生代太小,对象还没用多久就被YGC回收,或者晋升到老年代太快。

# 调大新生代(默认新生代占整个堆的1/3) -Xmn512m # 或者调整新生代与老年代比例 -XX:NewRatio=2 # 新生代:老年代 = 1:2 # 如果大对象直接进老年代,调大这个阈值 -XX:PretenureSizeThreshold=1m

场景二:Metaspace触发Full GC

政务系统经常加载大量动态生成的JSP、反射类,Metaspace压力大。

# 调大Metaspace(默认256m,政务系统建议512m~1g) -XX:MaxMetaspaceSize=512m # 同时调大压缩类空间 -XX:CompressedClassSpaceSize=256m

场景三:Full GC (Ergonomics) 频繁

说明老年代增长太快,对象存活时间太长或者内存泄漏。

# 调大整个堆 -Xmx4g # 如果用的CMS,可以调整触发老年代回收的阈值 -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly # 如果用的G1,调整暂停时间目标 -XX:MaxGCPauseMillis=200

场景四:System.gc()作祟

参考另一篇博客《System.gc()的隐蔽陷阱》,直接加-XX:+DisableExplicitGC

第三步:验证——调了之后到底有没有用

参数改完不是万事大吉,必须验证。重启后继续盯着jstat -gccause,对比调参前后的数据:

# 调参前记录5分钟数据(导出到文件)jstat-gccause<pid>1000>gc_before.log&# 调参后记录5分钟数据jstat-gccause<pid>1000>gc_after.log&

关注这几个指标:

指标调参前调参后评判
FGC(Full GC次数/分钟)3~5次0次消除Full GC
FGCT(Full GC总耗时)累计增长快不再增长Full GC消除
YGC频率过高(>10次/秒)合理(1~5次/秒)新生代分配正常
O(老年代使用率)持续增长稳定没有内存泄漏

调参成功的标志:Full GC没有了。

一个健康的JVM,Full GC应该极少甚至没有。如果YGC频率高但每次都很快回收(LGCC一直是Allocation Failure,E区没有飙升到90%+),那是正常的,不用管。

实战案例:一体化平台GC调优

2023年给一个政务一体化平台做GC调优,过程如下:

诊断阶段

jstat -gccause盯了10分钟,发现:

  • YGC每秒3~4次——频率偏高
  • 每小时触发2~3次Full GC——LGCC显示Ergonomics
  • 老年代使用率每次YGC后都会涨一点,说明对象晋升太快

调参阶段

原始参数(.tomcat的setenv.sh):

JAVA_OPTS="-Xms2g -Xmx2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m"

调优后参数:

JAVA_OPTS="-Xms4g -Xmx4g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:NewRatio=1 -XX:+DisableExplicitGC"

关键改动:

  • 堆从2G扩到4G——应用服务器内存够用,何必省
  • Metaspace从256M扩到512M——政务系统JSP和动态类多
  • 新生代比例从1:2调到1:1——大量短生命周期对象在新生代就回收掉
  • 禁止System.gc()——防止第三方库触发无谓的Full GC

验证阶段

调参后运行一周,jstat -gccause显示:

  • YGC降到每秒1~2次
  • FGC次数:0——Full GC消失了
  • 老年代使用率稳定在35%左右,不再持续攀升

系统再也没有"卡一下"的现象。

常见误区

误区一:一上来就调G1

有些文章说"G1比CMS好,生产环境应该用G1"。不一定。如果你的堆不大(<8G),CMS或者甚至Parallel GC就够了。G1的目标是低延迟大堆,小堆用G1反而开销更大。

# 4G以下的堆,Parallel GC可能就够了(JDK 8默认) # 4G~16G,CMS或G1都可以 # 16G以上,推荐G1

误区二:把Xms和Xmx设成不一样的

# 不好:Xms2g -Xmx4g # 好:Xms4g -Xmx4g

Xms和Xmx不一样,JVM运行过程中会动态扩缩堆,扩容本身要Full GC来整理内存。既然服务器内存够用,就让它一开始就分配满,省去扩容的开销。

误区三:调了参数不管

见过有人在测试环境调了参数,发现"好像好一点"就上线了。没有量化数据支撑的调优等于白调。一定要用jstat -gccause前后对比,拿数据说话。

命令速查

# 诊断GC原因(最有用)jstat-gccause<pid>1000# 查看GC统计概览jstat-gcutil<pid>1000# 查看详细GC统计(含各区域大小)jstat-gc<pid>1000# 查看JVM当前参数jinfo-flags<pid># 查看堆内存分布jmap-heap<pid># 导出heap dump分析内存泄漏jmap-dump:format=b,file=heap.hprof<pid>

总结

JVM GC调优不神秘,就三步:

  1. 先诊断:用jstat -gccause看清GC原因,不要猜
  2. 再调参:对症下药,不要抄网上的"万能参数"
  3. 后验证:用数据对比调参前后效果,不要凭感觉

政务系统的JVM问题,80%是这三个原因:堆太小、Metaspace不够、System.gc()作祟。把这三个排查完,基本就解决了。


感谢豆包、智谱、OpenCode在写作过程中的辅助。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 10:42:26

立体匹配中的‘分组’艺术:手把手复现GwcNet的Group-wise Correlation代价体

立体匹配中的分组智慧&#xff1a;从零实现GwcNet分组相关代价体 在双目立体视觉领域&#xff0c;如何高效计算左右图像特征间的匹配代价一直是核心挑战。传统方法依赖手工设计的代价函数&#xff0c;而现代深度学习则让网络自动学习匹配规律。2019年CVPR提出的GwcNet创新性地…

作者头像 李华
网站建设 2026/4/18 10:39:31

抖音批量下载神器:3分钟学会无水印批量下载完整指南

抖音批量下载神器&#xff1a;3分钟学会无水印批量下载完整指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support…

作者头像 李华
网站建设 2026/4/18 10:38:38

暗黑3游戏自动化难题的终极解决方案:D3KeyHelper宏工具深度解析

暗黑3游戏自动化难题的终极解决方案&#xff1a;D3KeyHelper宏工具深度解析 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面&#xff0c;可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper 在暗黑破坏神3的高强度刷…

作者头像 李华
网站建设 2026/4/18 10:33:44

3步高效实现OBS多平台同步直播:Multi RTMP插件深度实战指南

3步高效实现OBS多平台同步直播&#xff1a;Multi RTMP插件深度实战指南 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp 你是否为多平台直播的繁琐操作而烦恼&#xff1f;每次直播都要在…

作者头像 李华
网站建设 2026/4/18 10:30:19

Phi-3-Mini-128K商业应用:低算力成本构建私有知识库智能问答终端

Phi-3-Mini-128K商业应用&#xff1a;低算力成本构建私有知识库智能问答终端 想象一下&#xff0c;你是一家中小企业的技术负责人&#xff0c;老板希望为内部文档和产品手册搭建一个智能问答系统&#xff0c;方便员工随时查询。你调研了一圈&#xff0c;发现市面上的大模型方案…

作者头像 李华