面试官问JVM调优,你张口就是-Xms、-Xmx、-XX:+UseG1GC,背得滚瓜烂熟。对方听完,面无表情地在本子上画了个圈。这个圈的意思是:这人背过八股文,但没真调过。JVM调优不是参数默写比赛,是诊断思维和工程判断的较量。能把参数背出来的人一抓一把,能讲清楚“为什么调、怎么定位、调完效果如何”的人,才是面试官想聊下去的对象。
别上来就谈参数,先问一句“出了什么问题”
调优的前提是故障。没有病,吃什么药?面试时遇到“你怎么调优”这种问题,先反问场景:是频繁Full GC导致停顿过长,还是内存溢出OOM,还是CPU飙高伴随GC线程占满?不同症状对应不同药方。吞吐量优先的应用和响应时间优先的应用,GC策略截然不同。不问症状就开药,是庸医;不问场景就调参,是莽夫。老子说“知人者智,自知者明”,调优的第一步是自知——知道系统到底病在哪。
GC日志是唯一的证据,不是感觉
很多人调优靠“感觉”,觉得堆越大越好,觉得G1一定比CMS强。这是拍脑袋。正确的做法是开启GC日志:-Xlog:gc:file=gc.log:time,uptime,level,tags,然后用GCViewer或GCEasy分析。看什么?看Young GC频率、Full GC次数、单次停顿时间、晋升老年代速率。如果Young GC每秒好几次,说明新生代太小;如果Full GC频繁且每次回收不了多少,说明有内存泄漏。数据不会说谎,感觉会。面试时你能说出“我先看GC日志里的Allocation Failure和Humongous Allocation”,面试官就知道你亲手干过。
内存泄漏和内存溢出,两码事
OOM分两种:堆内存溢出和元空间溢出。堆溢出可能是泄漏,也可能是真不够。泄漏的典型特征是:每次Full GC后老年代占用不降反升。用jmap dump堆快照,MAT或JProfiler找支配树,定位哪个对象持有大量引用。元空间溢出多半是动态生成类太多,比如CGLIB代理滥用。别把泄漏当不够,加内存只能拖延崩溃,不能根治。面试时区分清楚这两者,是基本功。
调优的终点是业务指标,不是GC指标
GC停顿从200ms降到50ms,然后呢?业务QPS提升了吗?TP99下降了吗?如果GC优化了但业务没变,说明瓶颈根本不在这里。JVM调优永远服务于业务目标。响应时间敏感的系统,优先选低停顿收集器,比如ZGC或Shenandoah;吞吐量敏感的系统,Parallel GC可能更合适。脱离业务谈调优,就像脱离战场谈兵法,纸上谈兵。面试时你能把GC指标和业务SLA挂钩,层次立刻不一样。
一个真实案例胜过十页理论
准备一个你亲手调优的案例。比如:某服务每天凌晨Full GC持续十几秒,观察发现是老年代有个定时任务加载全量数据到本地缓存,导致对象朝生夕死却晋升老年代。解决方案是改成本地缓存加弱引用,或者调整Survivor区比例让短命对象留在新生代。最后Full GC从每天十几次降到几天一次。案例要讲清楚:现象、工具、分析、决策、结果。这才是STAR法则在JVM调优里的应用。
面试官眼前一亮,是因为你展现了思维过程
参数可以查,工具可以学,但诊断思维和权衡取舍的能力,是查不来的。面试官想听的是:你如何从现象出发,用工具验证假设,再根据业务约束做选择。调优不是炫技,是带着镣铐跳舞。内存、CPU、延迟、吞吐量,四个维度互相拉扯,你要找到当前场景下的最优解。能把这个过程讲清楚的人,面试官自然会给出那个圈——不是画掉你,是圈定你。