【JVM常见面试题】

JVM常见面试题

1.什么是JVM

  • JVM(Java Virtual Machine,Java虚拟机)是用于运行 Java 字节码的虚拟机进程。它是 Java 实现跨平台能力的核心,能够将 Java 程序编译为与平台无关的字节码,并根据操作系统将其转换为可直接执行的机器码。JVM 负责管理应用程序的内存,包括内存分配和垃圾回收,确保程序的高效运行。

2.JVM的内存模型

  • 方法区:存放已经被虚拟机加载的类信息、常量、静态变量等数据,是线程共享区域。
  • 堆:存放对象的实例和数组,线程共享,是垃圾回收的主要区域。
  • 虚拟机栈:每个线程都有自己的虚拟机栈,属于线程私有的内存区域。当线程执行一个方法时,会在栈中压入一个栈帧。每个栈帧包含局部变量表、操作数栈、动态链接和方法返回地址等信息。
  • 本地方法栈:服务于本地方法调用,类似于java虚拟机栈,但服务的是Native方法。
  • 程序计数器:跟踪当前线程的字节码指令,每个线程都有自己独立的程序计数器,用于保存下一条要执行指令的地址。

3.类的加载过程

  • 加载:读取.class文件数据到内存,创建class对象
  • 链接:
    • 验证:确保类文件的字节码符合JVM规范,保证安全性。
    • 准备:为静态变量分配内存,将其初始化为默认值。
    • 解析:将常量池中的符号引用转换为直接引用。
  • 初始化:对静态变量和静态代码块执行初始化。

4.有哪些类加载器?

  • 类加载器(ClassLoader)是负责将字节码文件加载到JVM的模块。主要包括以下几类:
    • 启动类加载器(Bootstrap ClassLoader),主要加载java核心类库(通常是jre目录下的lib目录),它是整个类加载系统的根加载器。位于其他所有类加载器之上。
    • 扩展类加载器(Extension ClassLoader),主要加载java的扩展库(jre目录下lib目录下的ext中的文件),位于启动类加载器和应用程序类加载器之间。
    • 应用程序类加载器(Application ClassLoader),也被称为系统类加载器,主要负责加载位于classpath路径下的所有类和jar文件,包括用户编写的类和依赖的第三方库。
    • 自定义类加载器,通过继承ClassLoader来实现自定义加载逻辑。

5.什么是双亲委派

  • 双亲委派是一种类加载机制,其中类加载器尝试加载类时,首先会委派给父类加载器尝试加载,直到最顶层的启动类加载器。如果父类加载器无法加载该类,子类才会尝试自行加载。这种模式保证了java核心库的类型安全,避免了类的重复加载。

6.堆和栈的区别

  • 堆(Heap):动态分配内存,存储对象的实例。生命周期较长,由垃圾回收期管理,线程共享。
  • 栈(Stack):存储局部变量和方法调用,生命周期较短,随方法的执行开始和结束。每个线程拥有自己的栈。

7.如何判断对象可以被回收

  • 引用计数法:给对象添加一个引用计数器,每当一个地方引用它时,计数器加一,引用失效时计数器减一,当计数器值为0时,对象不再被使用,执行垃圾回收时,即可被回收。有个缺点就是循环引用问题,引用计数法无法处理对象之间的循环引用,例如A引用B,B引用A,这种情况下,引用计数器不会为0,导致内存泄漏。
  • 可达性分析算法:从一系列的根对象(GC Roots)开始向下搜索,搜索所经过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,即证明该对象不再被使用,执行垃圾回收时,即可被回收。

8.你知道有哪些垃圾回收算法?

  • 标记-清除:先标记出所有要回收的对象,然后统一清除这些对象。优点:实现简单。缺点:会产生大量的内存碎片,影响大对象分配。
  • 复制:将内存划分为两部分,每次只使用其中一部分,执行垃圾回收时,将正在使用的内存中活动的对象复制另一块未被使用的内存中,然后清除正在使用的内存中所有的对象。优点:效率高,没有内存碎片,适合新生代。缺点:内存利用率低。
  • 标记-整理:首先标记出所有的存活对象,然后将这些对象移动到内存的一端, 最后清除边界外的对象。优点:相比标记清除,标记整理解决了内存碎片问题。缺点:移动对象成本较高,效率低于复制算法。
  • 分代回收算法:将堆内存分为新生代和老年代,新生代采用复制算法,老年代采用标记整理或标记清除。新生代包括一个伊甸园区(Eden)和两个幸存者区(Survivor From 和 To),新生代中的对象大部分都是朝生夕死,生命周期较短。新创建的对象一般都会被分配在新生代中的伊甸园区中,当伊甸园区内存不足时会执行Minor GC,通过可达性分析算法找到存活的对象,复制到幸存者To区,清除伊甸园区不再被引用的对象,幸存者To和幸存者From交换(就是From变成To,To变成From),同时对象的年龄加一,当伊甸园区内存再次不足时,会再次根据可达性分析算法找到存活的对象,将伊甸园区和幸存者From中存活的对象复制到幸存者To中,清除伊甸园区和幸存者From中的垃圾对象,再将幸存者To和幸存者From进行交换。同时对象年龄加一,当年龄超过一定阈值时(默认是15次),将被晋升到老年代。老年代中存放的就是在新生代中经过多次垃圾回收依然存活的对象(不过也有特殊情况,如果新生代中没有足够的空间来存放一个较大的对象,这些对象会被直接分配到老年代)。当老年代空间不足是时,会执行Full GC。

9.什么是永久代

  • 永久代是JVM内存模型中的一部分,用于存储类的元数据,静态变量,常量池方法信息。在jdk8及以后,被元空间取代,原因:永久代固定大小,容易引发OOM,而元空间在本地内存中分配,动态调整大小,元空间将类的元数据存放在堆外内存,降低了GC压力。

10.什么是STW

  • Stop The World(STW),指的是垃圾收集过程中,虚拟机暂停所有应用线程的执行,以确保在清理内存时不会有新的数据改动。保证垃圾收集的安全性和一致性,STW是收集过程中的一部分,影响程序的暂停时间。

11.JVM的主要组成部分

  • 类加载器:负责加载类文件
  • 运行时数据区:包括堆、方法区、程序计数器、虚拟机栈、本地方法栈。
  • 执行引擎:执行类文件中的指令。
  • 本地库接口:连接和管理本地库(Native Library),允许java调用本地引用程序和库。
  • 垃圾收集器:管理和回收内存。

12.什么是内存泄漏?

  • 内存泄漏是指程序中已被分配的内存由于某种原因未能释放,导致随着程序运行时间的增长,越来越多的内存无法被使用,导致可用内存逐渐减少,最终可能导致程序性能下降或崩溃的现象。

13.常用的JVM垃圾回收器有哪些?

  • Serial GC (串行垃圾回收器)
    • 特点:单线程工作,适用于单核或者低内存环境
    • 适用场景:适合小型应用或不需要高并发的场景
    • 使用方法:-XX:+UseSerialGC
  • Parallel GC (并行垃圾回收器)
    • 特点:多线程垃圾回收,注重吞吐量
    • 适用场景:适合CPU资源较多、要求高吞吐量的场景
    • 使用方法:-XX:+UseParallelGC (JDK8默认)
  • CMS GC (Concurrent Mark-Sweep)
    • 特点:采用标记-清除算法,可以再应用运行期间并发进行回收,减少停顿时间
    • 适用场景:适合对响应有较高要求的应用
    • 使用方法:-XX:+UseConcMarkSweepGC
    • 缺点:在回收碎片时可能会产生Full GC ,并且会消耗较多CPU资源
  • G1 GC (Garbage-First)
    • 特点:分区分代管理内存,优先回收垃圾最多的区域,以达到高效回收和低停顿的效果
    • 适用场景:适合大型内存应用,能均衡停顿时间和吞吐量
    • 使用方法:-XX:+UseG1GC (默认在JDK9及以上版本)

14.常用的JVM调优参数有哪些?

  • 堆设置:
    • -Xms:设置堆的初始大小
    • -Xmx:设置堆的最大大小
    • -Xmn:设置新生代大小(对于Parallel GC)
  • 垃圾收集器设置:
    • -XX:+UseSerialGC
    • -XX:+UseParallelGC
    • -XX:+UseConcMarkSweepGC
    • -XX:+UseG1GC
  • 性能优化:
    • -XX:SurvivorRatio:设置Eden区和Survivor区的大小比例
    • -XX:NewRatio:设置老年代与新生代的堆空间比例
    • -XX:MaxPermSize:设置永久代最大空间(java8之前)
    • -XX:MetaspaceSize:设置元空间初始大小(java8及以后)
    • -XX:UseStringDeduplication:开启G1垃圾收集器的字符串去重功能
  • 调试和监控:
    • -XX:+PrintGCDetails:打印垃圾回收的详细信息
    • -XX:+PrintGCDateStamps:在垃圾收集日志中添加时间戳
    • -Xloggc:<filename>:将垃圾回收日志写入文件
    • -XX:+HeapDumpOnOutOfMemoryError :在内存溢出时生成堆快照文件
    • -XX:HeapDumpPath=/path/to/directory/heapdump.hprof:将生成的堆快照文件保存到指定的路径和文件名中
  1. Minor GC 、Major GC、Full GC三者区别及触发条件?
  • Minor GC:清理新生代的垃圾,触发条件:当新生代空间不足时触发,即新生成的对象填满新生代的Eden区时。
  • Major GC:主要针对老年代的垃圾收集过程,速度比Minor GC 慢。触发条件:老年代空间不足时触发,或者在Minor GC 后存活对象转移到老年代填满可用空间时。
  • Full GC:对整个堆以及方法区的垃圾回收,是最耗时的GC,会造成较长时间的停顿。触发条件:调用System.gc(),老年代空间不足时,方法区空间不足时,极少数情况下通过 JNI 分配大量堆外内存导致堆外内存不足时,也可能触发 Full GC。

16.JVM中都有哪些引用类型?

  • 强引用(Strong Reference):普通的对象引用,只要强引用还存在,垃圾回收器就不会回收被引用的对象。Object obj = new Object();
  • 软引用(Soft Reference):通过SoftRefReference类实现,在垃圾回收中,只有当内存不足时,才会尝试回收软引用指向的对象。适合用来实现内存敏感的缓存。SoftReference softRef = new SoftReference<>(new Object());
  • 弱引用(Weak Reference):通过WeakReference类实现,比软引用更弱,JVM 每次进行垃圾回收时,都会回收弱引用指向的对象,无论内存是否紧张。适合用来存储那些偶尔需要但并非必须的对象。WeakReference weakRef = new WeakReference<>(new Object());
  • 虚引用(Phantom Reference):通过 PhantomReference 类实现,最弱的一种引用关系,不会决定对象的生命周期,只是用来跟踪对象的回收状态,必须与引用队列(ReferenceQueue)联合使用。
    • ReferenceQueue queue = new ReferenceQueue<>();
    • PhantomReference phantomRef = new PhantomReference<>(new Object(), queue);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值