大家好,我是程序员鱼皮。
相信很多学 Java 后端的朋友会在简历上写 “熟悉 JVM、熟悉 JVM 内存结构、熟悉 JVM 垃圾回收机制” 之类的吧?
勇敢点的朋友,甚至还会写 “熟悉 JVM 调优、有线上 JVM 故障排查的经历” 等等。
因为大家默认 JVM 是一个高大上的技术,认为简历上写 JVM 就能给简历加分。这确实没错,但是我个人的建议是,对于自己完全不了解、或者不够了解的技术,尤其是经历类的内容,不要轻易地写到简历上。
为什么?因为你写在简历上的所有内容,都有可能在面试时被面试官拿来问。
就像你写个 “了解 JVM”,有点儿水平的面试官都知道你其实就是不怎么了解,估计就是背了点儿八股文,面试的时候随便问一问,估计就暴露水平了。
尤其是 JVM 这种底层技术,可问的内容太多了,我大三暑假面试阿里的时候就被面试官问 JVM 疯狂吊打。。。
这不,前段时间我直播模拟面试了一位 25 届的学弟,简历上写了 JVM 相关的内容,而且他是真的有过 JVM 调优经历的,还是被我狠狠吊打了!
具体面试过程可以看视频:https://www.bilibili.com/video/BV1JM4m1m7Sr/
下面也用文字简单还原一下 JVM 相关的面试过程:
JVM 面试现场面试官:我看你的简历上有这么多加粗的技术,如果让你挑一个认为有难度的、相对最熟悉的技术,你会挑哪一个?
学弟:JVM 虚拟机吧
面试官心想:学弟这么猛么?!一上来就聊 JVM?这不得好好问一问
面试官:你有 JVM 线上调优的经历么?分享一下
学弟:有的,我们做智能货柜业务,员工下班后会去我们的智能货柜买水,由于园区内有 200 台设备,并发量较高,就导致服务器因为 JVM 频繁 Full GC 而告警。
面试官心想:感觉有点奇怪啊。。。
总共才 200 台设备,而且是线下购买这种场景,同时会有这么多人买水么?而且这个并发量也不大啊,怎么这就频繁 Full GC 了?解释一下,Full GC 是 JVM 中的一种垃圾回收机制,它会对整个堆内存(包括新生代和老年代)进行回收。Full GC 通常会导致应用程序暂停(Stop-The-World,简称 STW),因为 JVM 需要冻结所有的应用线程来进行内存的整理和回收,所以我们应该尽量避免程序出现 Full GC。
学弟接着说:经过导师和我的排查,发现是 JVM 频繁 Full GC,然后我们就调整了一下 JVM 堆内存的结构,比如把新生代老年代的比例调整成为 1 : 1,Eden 区和 Survivor 区的比例调整为 2 : 1 : 1。
面试官心想:更奇怪了。。。
听起来更像是业务代码层面的问题,这就已经开始调整 JVM 堆内存结构了么?调大新生代的占比(从 1/3 调到 1/2)的确有可能减少对象晋升到老年代的概率,但是 Eden 区和 Survivor 区的比例调整为 2 : 1 : 1 是什么鬼?一般默认是 8 : 1 : 1,Eden 区的作用是存放新创建的对象,Eden 区调整成那么小,不是很快就被填满从而触发 Minor GC 了么?面试官心想:不行,我得确认一下这个方案是谁想的。
面试官:你刚才提到导师带你去做了 JVM 调优嘛,那你具体做了什么?方案都是导师想的么?
学弟:调优方案是我们一起讨论的。
面试官:那有分析出来是什么对象占用了内存,有没有考虑过其他的解决方案?不调整占比能解决么?
学弟:可以用缓存,或者提前加机器扩容!
面试官心想:来了来了,经典的遇事不决就加机器。
面试官:再确认一下,应该是有一段时间并发量比较大,对象创建频繁,或者有对象没有及时释放,才导致了这个问题对吧?
学弟:是的,因为一开始对象进入新生代,默认比例 8 : 1 : 1,因为新生代执行 Minor GC 回收完后,对象所需内存还大于 Survivor 区,对象就会直接进入老年代,所以会产生 Full GC。
面试官心想:这个思路其实是 ok 的,可以通过增大 Survivor 区减少对象过早晋升到老年代的情况。但是这也意味着 Eden 区的空间减小,会更频繁触发 Minor GC、增加 Minor GC 的停顿时间;同时如果 Survivor 区太大,而幸存对象并没有那么多,可能会造成内存浪费。所以一般调整 JVM 参数要通过分析测试选取一个平衡点,否则可能会影响其他的功能。
面试官:如果因为这个功能就调整了 JVM 的参数,会不会影响该 JVM 上的其他业务?
学弟:额,这个当时没有考虑,但我们是微服务架构,功能之间相互隔离,影响应该不大。
面试官:我个人认为调整 JVM 参数是一个非常重要、谨慎考虑和决定的操作,能通过修改业务代码解决,就先不要盲目调整 JVM。不过你给出的 “微服务” 的解释也是合理的。那有没有查出来是什么对象导致了 JVM 频繁 Full GC?
学弟:额,当时定位到是 “购买对象”,用户每次扫码支付都会创建这个对象。
面试官心想:购买对象能占用这么多内存?你们到底是有多少人同时购买啊喂!
面试官:那这个对象到底存了什么结构?为什么占用那么多空间?为什么没有被及时释放?
学弟:(又解释了一遍 JVM 垃圾回收的流程),我觉得不是代码问题,就是因为 JVM 空间分配不均匀。
面试官心想:还是没有回答对象到底存了什么结构呀,JVM 招你惹你了,怪他空间分配不均匀?
学弟补充:因为审批服务器要走流程嘛,所以我们为了尽快解决这个问题,就直接调整了 JVM 比例,感觉比较快。
面试官:那我想问一下,如果并发再高一些,这个问题还会出现么?
学弟:会吧?为什么不会?这个我没想到。
面试官心想:当然会啊,因为你的这种解决方案治根不治本。再问个小问题来确认下这个经历的真实性吧。
面试官:你使用了什么工具来定位到底是哪一个对象占用了比较多的内存?或者没有及时释放?
学弟:我们有线上监控告警系统,
面试官:所以使用了公司的工具对吧,那如果我们自己来排查,怎么办?
学弟:把对象 dump 下来,然后用 jmap、jconsole、jvisualvm 之类的去分析。
面试官心想:还可以,起码听说过这些工具,但 jmap 主要是用来生成 dump 文件的。
面试官:MAT 有用过么?
学弟:MAT?哦,jmap 嘛?
面试官:不是不是,MAT 是 Eclipse 的一个内存分析工具。
学弟:没有用过,自己平时的项目也不会做 JVM 分析。
面试官:这个是真话哈哈,如果项目用得到的话就不会有那么多同学在 JVM 方面被拷打了。
面试建议通过面试,能感觉到这位同学是真的在公司接触过 JVM 的。但是对 JVM 的理解并不深刻,也没有深入思考过 JVM 的调优方案,所以建议遇到 JVM 线上问题时,一定要多用工具分析分析,除了调参之外,尽量多从源头去思考问题的解决方案。
毕竟是模拟面试,我是采用了引导式的面试方式,是从候选人自己的简历和经历出发去提问。由于候选人的回答比较浅显,所以我也没有问更深入更底层的问题:比如讲解一下垃圾回收器的染色算法、G1 垃圾回收器的原理、JIT 编译器和逃逸分析、指令重排序、停顿时间优化、分代收集算法等等。
所以也要提醒朋友们,如果要在简历上写 JVM,还是要做足准备的。也不建议像这位学弟一样,把 JVM 说成自己相对最熟练的技术,说个 MySQL、Redis、MQ 啥的难度会低很多。
更多编程学习交流:编程导航:https://www.code-nav.cn
简历快速制作:老鱼简历:https://laoyujianli.com
面试刷题神器:面试鸭:https://mianshiya.com