【面试八股|JVM虚拟机】JVM虚拟机常考面试题详解

📅 发布时间:2026/7/4 14:44:44 👁️ 浏览次数:
【面试八股|JVM虚拟机】JVM虚拟机常考面试题详解
这里根据个人说话口吻等编写JVM虚拟机常见面试题用于记录复习后续会持续更新补充欢迎点赞收藏。JVMJVM是什么/JVM由哪些部分组成/JVM运行流程第一jvm是java虚拟机是java长度的运行环境。有一次编写到处运行自动内存管理垃圾回收的作用。第二jvm由类加载器运行时数据区执行引擎本地库接口组成。其中运行时数据区又由程序计数器堆栈方法区组成。第三首先类加载器将java代码转换为字节码。其次运行时数据区将字节码加载到内存并由执行引擎执行。最后执行引擎将字节码翻译为底层系统指令交由cpu执行并需要调用本地库接口完成整个程序的功能。什么是程序计数器/程序计数器的特点第一程序计数器记录着当前执行的字节码指令地址当切换线程时需要程序计数器来告诉被挂起的线程上一次执行到哪里了。第二程序计数器是私有的唯一不会oom的区域什么是java堆/java堆的特点第一java堆是用于保存对象实例数组等信息的区域。是线程共享的。当堆被占满时会抛出oom的异常第二堆被划分为了年轻代和老年代年轻代包含eden区和s0s1区。第三在java8时将堆上的永久代方法区移动到了本地内存叫做元空间方法区介绍一下方法区第一方法区是用于存放类和方法元数据以及常量池的区域。是线程共享的。第二方法区在java8之前在堆中被叫做永久代java8及之后在本地内存中被叫做元空间第三方法区的移动主要由于其经常出现oom需要对其优化灵活管理。以及促进hotspot jvm与jrockit vm融合jrockit vm没有永久代。常量池是什么可以看作一张表虚拟机根据这张表去查找需要执行的类名方法名类型参数等。常量池是*.class文件中的当该类被加载常量池信息会放入运行时常量池并将符号地址变为真实地址。介绍一下虚拟机栈第一虚拟机栈是每个线程运行时需要的内存空间描述的是方法执行时的内存模型,是线程私有的。第二虚拟机栈由多个栈帧组成保存着局部变量动态链接信息方法返回地址等。垃圾回收是否涉及栈一般不涉及在栈帧弹出栈时内存会自动回收方法内局部变量是否线程安全一般是线程安全的但如果局部变量引用了对象并逃离方法的作用范围则需要考虑线程安全问题栈内存溢出1.栈帧过多递归调用stackoverflowerror2.栈帧过大导致内存溢出直接内存是什么直接内存属于虚拟机的系统内存但不受jvm内存管理。常见于NIO操作用于数据缓冲区分配回收成本高但读写性能好堆与栈的区别1.堆是线程共享的栈是线程私有的2.堆内存溢出报oom堆内存溢出报sof3.堆一般存储实例对象数组等栈一般存储局部变量方法调用等。堆会gc回收内存栈不会。什么是类加载器第一jvm只能运行二进制文件而类加载器负责将字节码文件加载到jvm中第二类加载器包括启动类加载器扩展类加载器应用类加载器自定义类加载器第三启动类加载器由c编写加载JAVA_HOME/jre/lib目录。扩展类加载器用于加载JAVA_HOME/jre/lib/ext。应用类加载器用于加载自己编写的java类什么是双亲委派机制在类加载器接到加载类的请求时它不会立刻加载而是委派到父类加载器完成依次迭代。如果父类加载器可以完成类加载任务则返回成功。只有当父类加载器无法完成加载任务才会由下一级加载为什么使用双亲委派机制1.可以避免某个类被重复加载确保类加载的唯一性2.可以保证类库API不被修改确保类加载的安全性说说类加载的过程类加载生命周期包含了加载-验证-准备-解析-初始化-使用-卸载其中验证-准备-解析统称为连接。加载通过类全名加载类到jvm二进制字节流在堆中创建Class实例访问入口验证验证文件格式魔数版本号常量池格式元数据父类是否存在是否存在继承final类字节码类型匹配无栈溢出符号引用引用的类方法字段是否存在是否有访问限制准备为类变量设置默认值分配空间为final static 初始化解析符号引用变为直接引用初始化生成执行static变量赋值语句static{}代码块clinit()方法,初始化父类优先六种类初始情况1.首次new类实例2.调用类静态变量/方法3.反射访问类/jvm启动时执行main方法所在类/动态语言支持如invokedynamic指令使用创建实例调用实例方法变量卸载触发条件-类实例均gc回收加载该类的类加载器被回收类Class实例无任何引用如反射引用也被释放java垃圾回收是什么为让程序员更专注代码实现而不用过多考虑内存释放问题java语言中有了自动的垃圾回收机制也就是GC。有了垃圾回收机制程序员只需要关注内存申请即可内存的释放由系统自动完成。对象什么是可被回收第一当对象被定义为垃圾时即可被回收这里有两种方式判断什么是垃圾第二首先是引用计数法在一个对象头上增添其被引用的次数如果次数为0则该对象可被回收。其次是可达性分析算法被gcroot指向或被间接指向的对象不可被回收不可被回收引用计数法的优缺点优点实时性较好可根据计数器是否为0直接回收。区域性更新对象计数器不会扫描全部对象。缺点存在循环引用问题有可能导致内存泄露。浪费cpu资源需要不断运行计数器统计。有哪些常见的gcroot局部变量静态变量静态常量JNI的对象引用Native方法中的引用有哪些垃圾回收算法第一标记清除算法通过可达性分析算法对垃圾标记然后对标记的垃圾清除第二标记整理算法通过可达性分析算法对垃圾标记然后在清除垃圾过程中将存活对象向一边移动第三复制算法将原有空间一分为二将正在使用的对象复制到另一内存空间然后清除该内存空间交换两个内存的角色这些垃圾回收算法的特点1.标记清除算法效率低需要两次遍历全部对象。体验差gc时需要停止应用程序。内存碎片化严重2.标记整理算法相对于标记清除算法多了一步整理因此性能更低。但解决了内存碎片化问题。3.复制算法每次只能使用一半内存空间利用率低。但垃圾对象较多时效率高。并且没有碎片内存。介绍分代收集算法第一分代收集算法是jvm垃圾回收的基础设计思想第二在java8时堆被分为了新生代和老年代默认内存空间比例为12。新生代又被分为了edens0s1区默认内存空间比例为811第三具体情况为1.当创建对象时会被分配到eden区。2.当eden区满了会触发young gc 清除eden区并把存活对象转移到s0年龄加1。3.再触发young gc清除eden区与s0区把存活对象转移到s1区。 4.当某对象年龄达到某一阈值默认为15会转移到老年代。这里也存在特殊情况如果进入eden区的是大对象那在第一次young gc就会转移到老年代。5.老年代也满了会触发full gc同时回收新生代和老年代并且除执行full gc的其它线程都会被挂起。因此我们要尽量避免full gc新生代老年代永久代区别新生代主要存放新生对象老年代存放生命周期较长的对象永久代指依旧保存的的区域主要是方法类的元数据。jvm的常见垃圾回收器以及特点第一常见垃圾回收器串行垃圾回收器并行垃圾回收器CMS并发垃圾回收器g1垃圾回收器第二串行垃圾回收器serial作用于新生代使用复制算法。serial old 作用与老年代使用标记整理算法。一个线程垃圾回收其它线程阻塞并行垃圾回收器jdk8默认垃圾回收器parallel new作用于新生代使用复制算法。parallel old作用于老年代使用标记整理算法。多个线程垃圾回收其它线程阻塞CMS并发垃圾回收器目的停顿时间最短针对老年代标记-清除算法。初始标记-并发标记-重新标记-并发清理。阻塞-不阻塞-阻塞-不阻塞。g1垃圾回收器jdk9默认使用兼顾响应时间和吞吐量复制算法。划分多个区域每个区域都可以作为edensurvivoroldhumongous区。回收过程包括年轻代垃圾回收并发标记老年代占用超45%两次标记不暂停线程和暂停线程混合回收如果并发失败再full gc。强引用弱引用软引用虚引用区别1.gcroot连接只有强引用不连接时才被回收核心逻辑2.softreference 垃圾回收后内存还不足才回收缓存场景3.weakreference无论内存是否充足都被回收临时关联4.phantomreference配合队列使用无法通过引用获取实例资源通知Jvm参数在哪配置1.springboot项目运行jar包时2.tomacat配置参数修改.sh文件常用jvm调优参数1.设置堆最小与最大大小-Xms设置堆的初始化大小-Xmx设置堆的最大大小2.设置年轻代老年代的比例老年代为堆大小-年轻代-XX:newSize 设置年轻代的初始大小-XX:MaxNewSize 设置年轻代的最大大小 初始大小和最大大小两个值通常相同3.设置年轻代内eden与s区比例-XXSurvivorRatio3表示年轻代中的分配比率survivor:eden 2:34.堆栈设置默认1m但256k就够了-Xss 对每个线程stack大小的调整,-Xss128k5.设置年轻代到老年代的年龄阈值-XX:MaxTenuringThreshold6.设置垃圾回收器-XX:UseParallelGC:年轻代使用并行垃圾回收收集器。这是一个关注吞吐量的收集器可以尽可能的减少垃圾回收时间。-XX:UseParallelOldGC:设置老年代使用并行垃圾回收收集器。-XX:UseConcMarkSweepGC老年代使用CMS收集器降低停顿-X是快捷简写所有-X参数都有对应的-XX参数语法简单长期稳定常用的-Xms/-Xmx/-Xmn是堆调优的基础快捷参数-XX是调优核心分布尔型-开启 / 关闭和键值对型设置值覆盖 JVM 所有调优维度是精细控制堆分代、GC 收集器的唯一选择部分参数随版本变化JVM调优工具命令工具jps输出JVM中运行的进程状态信息(现在一般使用jconsole)jstack查看java进程内线程的堆栈信息。jmap用于生成堆转存快照jhat用于分析jmap生成的堆转存快照一般不推荐使用而是使用Ecplise Memory Analyzerjstat是JVM统计监测工具。可以用来显示垃圾回收信息、类加载信息、新生代统计信息等。可视化工具jconsole用于对jvm的内存线程类 的监控是一个基于 jmx 的 GUI 性能监控工具VisualVM能够监控线程内存情况查看方法的CPU时间和内存中的对 象已被GC的对象反向查看分配的堆栈java内存泄露排查思路1.首先通过jmap命令打印内存快照dump文件为避免某些情况打印不了可以通过设置vm参数的方式打印2.通过jdk自带的visualVM去分析dump文件3.查看堆信息情况定位哪行代码出现问题4.找到对应代码进行修改CPU飙高排查思路1.通过top命令查看cpu使用情况2.查看哪个进程使用cpu较高记录该进程id3.通过ps查看该进程的线程信息分析哪个线程占用cpu较高4.通过jstack查看线程详情记录问题代码行号进行解决