当前位置:   article > 正文

【面试题】JVM面试题及答案总结_jvm面试题总结及答案

jvm面试题总结及答案

JVM(Java虚拟机)是Java技术体系的核心,面试中经常会被问到与JVM相关的问题,

以下是一些典型的JVM面试题及答案概要:

JVM的主要组成部分有哪些?

  • 类加载器(ClassLoader):负责从文件系统或网络等位置加载.class文件,并将这些字节码转换成方法区的运行时数据结构。
  • 运行时数据区(Runtime Data Area):
    • 程序计数器(Program Counter Register):线程私有,存储当前正在执行的指令地址。
    • 虚拟机栈(Java Virtual Machine Stacks):线程私有,每个方法在执行时会创建一个栈帧(Stack Frame),用于存放局部变量表、操作数栈、动态链接和方法出口信息等。
    • 本地方法栈(Native Method Stack):与虚拟机栈类似,为虚拟机使用到的Native方法服务。
    • 堆(Heap):所有线程共享,存放对象实例以及数组。
    • 方法区(Method Area):所有线程共享,存储已被加载的类的信息、常量池、静态变量、即时编译器编译后的代码等数据
  • 执行引擎(Execution Engine):负责执行字节码,包括解释执行和通过JIT(Just-In-Time)编译器进行的热点代码优化编译执行。
  • 本地库接口(Native Interface):允许Java代码调用底层操作系统或硬件的接口。

Java内存溢出错误主要有哪些类型?

  • Java heap space out of memory error:堆空间不足,通常由于对象过多或者单个对象过大导致。
  • PermGen space out of memory error (或Metaspace for Java 8以上版本):方法区空间不足,常见于大量类的动态加载或者反射生成大量类信息时。
  • StackOverflowError:虚拟机栈或本地方法栈深度过深,如递归调用层次太深且未及时返回导致栈空间耗尽。
  • DirectBuffer分配内存溢出:直接内存(Direct Memory)超过其上限。

什么是垃圾收集(GC)?GC算法有哪些?

垃圾收集是JVM用来自动回收不再使用的对象所占用的内存的过程。常见的垃圾收集算法包括:

  • 标记-清除(Mark-Sweep):先标记出所有活动对象,然后清除未被标记的对象。
  • 复制(Copying):将内存划分为两块,只有一块用于分配对象,当这块内存满了之后,就将存活的对象复制到另一块上,然后清空已使用的那块区域。
  • 标记-压缩(Mark-Compact):结合了标记-清除和复制的思想,标记阶段找出所有活动对象后,压缩它们到内存的一端,消除碎片。
  • 分代收集(Generational Collection):基于年轻代(Eden, Survivor Space)和老年代(Tenured Generation)的不同特性,采用不同的收集策略,如新生代的Copying算法(如Parallel Scavenge)、老年代的Mark-Sweep-Compact算法(如Serial Old、Parallel Old)等。

什么是类加载机制,类加载过程包含哪几个步骤?

类加载机制是JVM实现把.class文件中的二进制数据转换为方法区中运行时数据结构的过程。类加载过程包括以下几个阶段:

  • 加载(Load):通过类的全限定名找到对应的.class文件并读入内存,创建一个代表该类的Class对象。
  • 验证(Verification):确保被加载类的正确性,例如检查类文件格式、元数据、字节码验证等。
  • 准备(Preparation):给类的静态变量分配内存,并初始化为默认值。
  • 解析(Resolution):将符号引用转换为直接引用,如将字符串常量池中的字符串引用解析为实际的内存地址。
  • 初始化(Initialization):执行类构造器方法,对静态变量进行初始化赋值。

JVM中的双亲委派模型是什么?

双亲委派模型是Java类加载器的一种工作模式。当一个类加载器收到类加载请求时,首先不会自己尝试加载,而是将这个请求委派给父加载器去完成。每一层次的类加载器都是如此,因此所有的加载请求最终都会传送到顶层的启动类加载器。只有当父加载器无法完成类加载(即找不到指定类)时,子加载器才会尝试自己去加载。

这样做的好处在于保证了Java应用的各个类库版本的一致性,避免了由于类重复加载而导致的安全性和稳定性问题。

Java对象什么时候可以被垃圾回收?

Java对象在以下条件满足时可以被垃圾回收:

  • 对象不再有任何引用指向它,无论是强引用、软引用、弱引用还是虚引用。
  • 对象是可达的,但其关联的引用类型已经进入相应的引用队列。
    具体来说,当一个对象没有任何途径再被程序访问到,也就是不可达时,将会被视为可回收的对象。垃圾收集器会在合适的时机进行回收操作。

请解释一下Minor GC和Full GC的区别?

Minor GC:发生在年轻代(Young Generation)的垃圾回收。年轻代包括Eden区和两个Survivor区,当年轻代空间不足时会触发Minor GC。 Minor GC相对频繁且速度较快,因为年轻代的对象生命周期通常较短,大部分对象会被回收。

Full GC:发生在整个堆内存中,包括年轻代和老年代(Tenured Generation)以及方法区(对于HotSpot虚拟机还包括元空间Metaspace)。Full GC一般发生在老年代空间不足,或者System.gc()显式调用,或者CMS并发清理失败等情况。Full GC比Minor GC更耗费时间,因为它涉及的对象范围更广,影响更大。


介绍一下JVM调优工具JConsole和VisualVM的作用?

JConsole:Java自带的一个GUI监控工具,用于对本地或远程Java应用程序进行性能监控和故障排查。它可以显示线程、内存、类加载、CPU使用率等信息,并支持动态查看MBean属性和执行MBean操作。

VisualVM:是一个功能更加强大的JDK工具套件,提供了更全面的应用程序分析功能,包括内存分析、线程分析、CPU分析、类加载分析等。VisualVM还支持插件扩展,可以安装如Memory Sampler、Thread Dump Analyzer等高级功能模块,帮助开发者深入了解JVM运行状态,进行性能瓶颈定位和JVM参数调优。


说说你了解的几种常用的JVM参数及其作用?

-Xms 和 -Xmx:分别设置Java进程初始堆大小和最大堆大小,例如 -Xms2g -Xmx4g 表示初始堆为2GB,最大堆为4GB。
-XX:NewRatio:设置年轻代与老年代的比例,默认值根据平台不同而不同,例如 -XX:NewRatio=3 表示年轻代与老年代的内存比例为1:3。
-XX:MaxTenuringThreshold:设置对象晋升到老年代的年龄阈值,默认值是15。年轻代中经历多次Minor GC后依然存活的对象将会晋升至老年代。
-XX:+UseConcMarkSweepGC 或 -XX:+UseG1GC 等:选择不同的垃圾收集器,比如CMS垃圾收集器或G1垃圾收集器。
-XX:PermSize 和 -XX:MaxPermSize(Java 8之前有效):设置永久代的初始大小和最大大小,但在Java 8及以后版本,永久代已被元空间(Metaspace)取代,相应参数为 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize。


什么是Java内存模型(JMM)?

Java内存模型(Java Memory Model, JMM)是一种规范,它定义了Java虚拟机如何与计算机硬件内存进行交互以及在多线程环境下如何同步和通信。JMM确保了并发编程中的原子性、可见性和有序性。它解决了由于处理器重排序、缓存一致性等问题可能带来的并发编程中的数据不一致问题。


解释一下JVM中的HotSpot及其优化策略?

HotSpot是Oracle JDK中使用的一种高性能的JVM实现,它采用了多种优化技术,包括:

**即时编译器(JIT):**HotSpot JVM包含多个即时编译器(C1、C2),将热点代码从字节码转换为机器码,通过方法内联、循环展开等优化提高执行效率。

**动态编译优化:**根据运行时数据对热点代码进行持续优化,例如分支预测、逃逸分析、栈上替换(On-Stack Replacement, OSR)等。

**垃圾收集优化:**提供不同的垃圾回收器如Serial GC、Parallel GC、CMS GC、G1 GC、ZGC和Shenandoah GC,并支持各种调优参数以适应不同应用的需求。


什么是类卸载机制?类何时会被卸载?

类卸载是指JVM从方法区中移除不再使用的类的信息,释放其占用的内存空间。类被卸载需要满足以下条件:

  • 类的所有实例都已被回收。
  • 加载该类的类加载器已经被回收。
  • 该类的Class对象没有在任何地方被引用,即不可达。

类卸载由系统自动进行,无需开发者显式操作,但需要注意的是,如果应用程序设计不当,可能会导致类永不卸载,从而引发长期运行的应用程序内存泄漏问题。


如何避免死锁的发生,尤其是在JVM中?

在JVM环境中避免死锁通常需要遵循以下原则:

  • 避免一个线程同时占有两个以上的资源而不释放已占有的资源。
  • 使用资源请求时设置超时时间,超时后主动释放持有的资源并重新尝试。
  • 按照既定的全局顺序申请资源,避免循环等待。
  • 尽量减少同步区域,只在必要的时候持有锁。
  • 使用高级并发工具,如java.util.concurrent包提供的锁、信号量和队列等,它们提供了更细粒度的控制和更高的容错性。

Java中有哪些常见的内存泄漏类型,并给出相应的解决方案?

常见的Java内存泄漏类型包括:

  • 静态集合类引起的内存泄漏:静态集合类会一直存活到应用程序结束,若其中存储的对象不再使用,也会无法被回收。解决方案是定期清理无用对象或在不再使用时手动从集合中移除。
  • 长生命周期对象持有短生命周期对象引用:当长生命周期的对象持有短生命周期对象的引用,而短生命周期对象不再使用时,由于强引用的存在,垃圾回收器无法回收这些对象。解决办法是适时断开不必要的引用,比如使用弱引用或软引用。
  • 监听器/回调函数未注销:注册到某个服务或者框架中的监听器或回调函数,如果没有正确地反注册,可能会导致对象不能被回收。应确保在组件不再使用时及时取消注册。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/960468
推荐阅读
相关标签
  

闽ICP备14008679号