前言:面试官的 “灵魂拷问” 套路
面试官:工作中做过 JVM 调优吗?说说你都调过啥?
我内心:咱项目 QPS 连 10 都摸不到,上次问缓存穿透雪崩,这次又整 JVM 调优,真就往死里为难人呗。
别怕!我给大家整理了一套超全的 JVM 调优干货,面试能吹、实战能用,直接一套带走。
一、JVM 究竟需不需要调优?
JVM 发展这么多年,早就被打磨得很稳了。我个人觉得,99% 的场景其实根本用不着手动调优。
平时我们配 JVM 参数,基本还是跟着官方推荐来就够用了:
这些默认参数,都是 JVM 团队经过大量测试、业界无数实践验证过的,正常用基本不会出什么大问题。
更何况,绝大多数项目 QPS 连 10 都不到,数据量也就几万级别,在这种低压力场景下,JVM 想出故障都难。
大家平时碰到的** OOM、CPU 飙高、GC 频繁**,多半都是代码问题导致的,改改代码就能解决,一般真没必要去动 JVM 参数。
连锁出现:GC 频繁 → CPU 高 → 最终 OOM
- 静态集合持有大量对象(最常见!)
// 静态List永远不会被GC,一直往里面塞数据,必OOM
private static List<Object> cacheList = new ArrayList<>();
public void addData(Object data) {
cacheList.add(data);
}
原因:静态变量属于类生命周期,只要类不卸载,集合就不会被回收,数据无限堆积。
场景:本地缓存、临时数据、日志、请求参数无限制存储。
解决:加大小限制、使用 LRU 缓存、用完清空、用弱引用。
- 无限递归(栈溢出 / 堆溢出)
结果:StackOverflowError 或 OOM。
原因:方法栈帧无限创建,耗尽栈 / 堆内存。
- 大对象 + 无限创建(一次性加载全表数据)
// 一次性查100万条数据到内存
List<User> list = userMapper.selectAll();
解决:分页、流式查询、分批处理。
- CPU 高:查死循环、正则、GC、序列化、密集计算
- GC 频繁:查循环 new 对象、大对象、内存泄漏(程序用不到的对象,却一直占着内存不释放,GC 想回收也收不掉,时间久了就会 OOM)
- OOM:查静态集合、全表查询、ThreadLocal、无界队列、未关闭资源 总结:
- OOM 核心:对象无法回收、无限堆积
- CPU 高 核心:死循环、GC 疯狂、密集计算
- GC 频繁 核心:临时对象过多、内存泄漏
- 三者常常互相触发,优先排查 GC 日志

二、升级垃圾回收器就能解决问题?
网上有种说法:JVM 调优没必要,直接升级垃圾回收器就行。这个观点值得商榷。
实战角度
升级垃圾回收器确实是最有效的方式之一:
- CMS → G1:性能提升明显,但 JDK8 中 G1 还存在不少问题
- G1 → ZGC:最大暂停时间不超过 10ms,甚至 1ms
GC 做清理内存时,**必须暂时停掉你的业务代码,**这个 “停掉业务” 的时间,就叫 STW(Stop The World)
- 停 100ms → 用户明显卡顿
- 停 500ms → 接口超时、页面卡死
- 停 1s → 系统雪崩
所以低延迟 GC 的核心目标:把 STW 压到极短,通常 1ms ~ 3ms
- 标记、清理、转移 … 大部分工作和业务代码并发跑
- STW 只做极少量根扫描,所以超快
G1 还要分段去做,停顿会随堆变大而变长。ZGC 停顿几乎不随堆大小变化。
但 ZGC 并不是银弹,已知问题有:
- 吞吐量下降:相较 G1 最大下降 15%
- 高分配速率场景:唯一有效的"调优"方式就是增大堆内存
没有最好的,只有最合适的。
面试角度
如果你只回答"升级垃圾回收器",面试官大概率没听到他想要的答案。所以:
可以回答升级垃圾回收器,但不能只回答升级垃圾回收器。
三、JVM 何时优化?
《计算机程序设计艺术》作者高德纳说过:
过早的优化是编程中所有罪恶的根源。
忌过早优化,但不是完全不管。正确做法是:给核心服务的 JVM 指标配上监控告警,当指标出现波动时及时介入。
- 新生代:放新创建的对象,回收频繁、速度快,对应 Young GC(YGC)。
- 老年代:放存活时间长的对象,回收少但慢,触发 Full GC(FGC)。
对象如何从新生代 → 老年代
- 新对象先进入 Eden
- Eden 满 → YGC,存活对象进入 Survivor
- 在 Survivor 来回拷贝,年龄达标 晋升老年代
- 或 大对象 直接进入老年代
- 老年代满 → 触发 Full GC
JVM 核心指标参考范围
FGC = Full GC,全称 Full Garbage Collection,日常大家说的 FGC 飙高、FGC 频繁,就是指 Full GC 太多、太频繁。
YGC / Young GC:只回收新生代
- 速度快
- STW 短
- 频繁一点问题也不大
FGC / Full GC:回收整个堆
- 新生代 + 老年代 + 元空间一起扫
- 速度极慢
- STW 很长,会直接导致服务卡顿、超时、雪崩
Grafana / Prometheus 里的指标:
jvm_gc_full_collections_totalFGC 总次数jvm_gc_full_collection_time_secondsFGC 总耗时
只要这几个指标正常,其他一般不会有问题。
四、JVM 优化步骤
分析和定位系统瓶颈
CPU 指标
JVM 内存指标
JVM GC 指标
这些都是临时文本日志,现在基本都用引入 actuator + micrometer,自动暴露 JVM 指标到 /actuator/prometheus
Prometheus 拉取指标,Grafana 导入 JVM 大盘(比如 4701、12856 等热门 dashboard)
最终你能在 Grafana 看到:
- GC 次数、耗时
- 堆内存趋势
- 年轻代 / 老年代变化
- 对象晋升
- STW 时间
- 元空间、直接内存
五、面试回答模板
当被问到 JVM 调优时,按以下逻辑回答:
- 表态:合理的 JVM 参数配置下,大多数情况不需要调优
- 补充:仍存在少量场景需要调优,应对核心指标配置监控告警
- 深挖:如果面试官追问分析方法,展示常用命令和工具
这一套流程下来,面试官对你的 JVM 功底会有不错的印象。
参考资料
- 本文整理自 程序员囧辉 - JVM 调优实战
- JDK 官方文档
- 《深入理解 Java 虚拟机》- 周志明
一句话总结:JVM 调优不是常规操作,但掌握分析方法很重要。监控先行,定位瓶颈,量化目标,逐步优化。
本文链接: https://hyuzz-nuc.github.io/posts/jvm-tuning-guide/
未经作者禁止转载!


