看了最新大厂面试,这 6 道 JVM 面试题都被问到了

前言

本系列会系统的整理 MySQL,Redis,SSM 框架,算法,计网等面试常问技术栈的面试题,本文主要是整理分享了 JVM 相关的面试题,MySQL、Spring 之前已经更新了,需要的同学也可以去看一下,希望对正在准备秋招的你们有所帮助!

JVM 面试题:

  • JVM 内存为什么要分成新生代,老年代

  • 新生代中为什么要分为 Eden 和 Survivor

  • JVM 中一次完整的 GC 流程是怎样的

  • CMS 收集器和 G1 收集器的区别

  • JVM 调优

  • CPU 飙升如何排查

当然个人整理的所有面试题都无偿分享,只求大伙一个点赞关注转发三连,这些文档都放在文末了,需要的同学可以自取

1. JVM 内存为什么要分成新生代,老年代?

1.1 JVM 共享内存划分

  • 共享内存区 = 持久代 + 堆(jdk1.8 及以上 jvm 废弃了持久代)

  • 持久代 = 方法区 + 其他

  • Java 堆 = 老年代 + 新生代

  • 新生代 = Eden + S0 + S1

1.2 为什么分年老代和新生代

  • 新生代:主要存放新创建的对象,内存大小一般会比较小,垃圾回收会比较频繁。

  • 老年代(Tenured Gen):主要存放 JVM 认为生命周期比较长的对象(经过几次的 Young GC 的垃圾回收后仍然存在),或者大对象,垃圾回收也相对没有那么频繁。

为什么划分老年代和新生代,主要对象大小不一样,对象生命周期不一样。划分后,提供垃圾回收效率,节省资源,提升对象利用率等等。

2. 新生代为何划分 Eden 和 Survivor?为什么设置两个 Survivor

  • 如果没有 Survivor,Eden 区每进行一次 Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发 Major GC.老年代的内存空间远大于新生代,进行一次 Full GC 消耗的时间比 Minor GC 长得多,所以需要分为 Eden 和 Survivor。

  • Survivor 的存在意义,就是减少被送到老年代的对象,进而减少 Full GC 的发生,Survivor 的预筛选保证,只有经历 16 次 Minor GC 还能在新生代中存活的对象,才会被送到老年代。

  • 设置两个 Survivor 区最大的好处就是解决了碎片化,刚刚新建的对象在 Eden 中,经历一次 Minor GC,Eden 中的存活对象就会被移动到第一块 survivor space S0,Eden 被清空;等 Eden 区再满了,就再触发一次 Minor GC,Eden 和 S0 中的存活对象又会被复制送入第二块 survivor space S1(这个过程非常重要,因为这种复制算法保证了 S1 中来自 S0 和 Eden 两部分的存活对象占用连续的内存空间,避免了碎片化的发生)

3. JVM 中一次完整的 GC 流程是怎样的

  • Java 堆划分为老年代和新生代

  • 新生代 划分为 Eden 和两个 Survivor(S0、S1)

  • 当 Eden 区的空间满了, Java 虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对象,则会转移到 Survivor 区。

  • 大对象(需要大量连续内存空间的 Java 对象,如那种很长的字符串)直接进入老年态;

  • 如果对象在 Eden 出生,并经过第一次 Minor GC 后仍然存活,并且被 Survivor 容纳的话,年龄设为 1,每熬过一次 Minor GC,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。即长期存活的对象进入老年态。

  • 老年代满了而无法容纳更多的对象,Minor GC 之后通常就会进行 Full GC,Full GC 清理整个内存堆 – 包括年轻代和年老代。

  • Major GC 发生在老年代的 GC,清理老年区,经常会伴随至少一次 Minor GC,比 Minor GC 慢 10 倍以上。

4. CMS 收集器和 G1 收集器的区别

  • CMS 收集器是老年代的收集器,一般配合新生代的 Serial 和 ParNew 收集器一起使用;G1 收集器收集范围是老年代和新生代,不需要结合其他收集器使用;

  • CMS 收集器是一种以获取最短回收停顿时间为目标的收集器, G1 收集器可预测垃圾回收的停顿时间

  • CMS 收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片;而 G1 收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。

  • CMS 和 G1 的回收过程不一样,垃圾回收的过程不一样。CMS 是初始标记、并发标记、重新标记、并发清理;G1 是初始标记、并发标记、最终标记、筛选回收。

5. JVM 调优

JVM 调优其实就是通过调节 JVM 参数,即对垃圾收集器和内存分配的调优,以达到更高的吞吐和性能。JVM 调优主要调节以下参数

堆栈内存相关

  • -Xms 设置初始堆的大小

  • -Xmx 设置最大堆的大小

  • -Xmn 设置年轻代大小,相当于同时配置-XX:NewSize 和-XX:MaxNewSize 为一样的值

  • -Xss 每个线程的堆栈大小

  • -XX:NewSize 设置年轻代大小(for 1.3/1.4)

  • -XX:MaxNewSize 年轻代最大值(for 1.3/1.4)

  • -XX:NewRatio 年轻代与年老代的比值(除去持久代)

  • -XX:SurvivorRatio Eden 区与 Survivor 区的的比值

  • -XX:PretenureSizeThreshold 当创建的对象超过指定大小时,直接把对象分配在老年代。

  • -XX:MaxTenuringThreshold 设定对象在 Survivor 复制的最大年龄阈值,超过阈值转移到老年代

垃圾收集器相关

  • -XX:+UseParallelGC:选择垃圾收集器为并行收集器。

  • -XX:ParallelGCThreads=20:配置并行收集器的线程数

  • -XX:+UseConcMarkSweepGC:设置年老代为并发收集。

  • -XX:CMSFullGCsBeforeCompaction=5 由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行 5 次 GC 以后对内存空间进行压缩、整理。

  • -XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片

辅助信息相关

  • -XX:+PrintGCDetails 打印 GC 详细信息

  • -XX:+HeapDumpOnOutOfMemoryError 让 JVM 在发生内存溢出的时候自动生成内存快照,排查问题用

  • -XX:+DisableExplicitGC 禁止系统 System.gc(),防止手动误触发 FGC 造成问题.

  • -XX:+PrintTLAB 查看 TLAB 空间的使用情况

6. CPU 飙升如何排查

  • 输入 jps,获得进程号。

  • top -Hp pid 获取本进程中所有线程的 CPU 耗时性能

  • printf %x cpu 最高的线程(即转为 16 进制)

  • jstack 命令查看当前 java 进程的堆栈状态 | grep 那个 16 进制

  • 或者 jstack -l > /tmp/output.txt 把堆栈信息打到一个 txt 文件。

资料领取

本文就先写到这里,面试中常问的一些题目我都有整理的,后面会持续更新,需要 PDF 的好兄弟可以点赞本文+关注后私信即可即可领取

猜你喜欢

转载自blog.csdn.net/weixin_70730532/article/details/125871400