§2.1.6 JVM调优实战案例
考察意图:验证完整的排查→定位→解决→验证闭环能力。
案例一:定时任务导致Full GC:
危废平台上线后,每周固定时间接口响应从200ms飙升到5秒以上。排查:jstat -gcutil看发现老年代每周末凌晨突增 → jmap -dump堆内存用MAT分析 → Dominator Tree发现HashMap缓了几百万条危废联单数据 → 根因是定时任务没做分页,一次load全量数据。解决方案不是调JVM参数,而是改代码——Caffeine本地缓存(最大条目+过期时间),定时任务改分批。改完后Full GC停顿从1.2秒降到100ms以内。教训:JVM调优很多时候改代码比改参数更有效。
案例二:Metaspace溢出:
生产环境切流量后运行12小时左右突然 OOM: Metaspace。排查:jstat -gcutil看MU(Metaspace使用率)接近100% → jmap -clstats看加载的类数量异常高(正常几千,它几百万)→ Arthas vmtool查看发现大量 com.sun.proxy.$ProxyXXX类 → 定位到Groovy脚本引擎每次执行规则都 new GroovyClassLoader()但没关 → ClassLoader泄漏导致反复加载同类→ Metaspace撑爆。解决:GroovyClassLoader改单例复用,加 -XX:MaxMetaspaceSize=256m兜底限流。
案例三:G1停顿时间优化:
G1 GC后P99延迟偶尔飙到800ms。排查GC日志发现Mixed GC的Cleanup阶段耗时400ms——老年代Region中大对象过多。-XX:G1HeapRegionSize从2MB调到4MB(让大对象进Humongous Region而非普通Old Region),加上 -XX:+ParallelRefProcEnabled并行处理Reference对象,-XX:MaxGCPauseMillis=100让G1自动收紧回收范围。优化后P99压到300ms以内。
陷阱提示:只讲成功案例不讲失败教训;编造数据(面试官可能现场让你画内存布局图)。