JVM面试合集

本文详细阐述了Java虚拟机JVM的架构组成,包括类加载器、运行时数据区、执行引擎和垃圾收集器。此外,还讲解了内存模型、类加载原理、垃圾回收算法以及常见问题如Cms收集器的配置和内存优化。

前言

前文介绍了数据库、中间件相关。本期我们继续学习Java特性的JVM。

JVM面试合集

  1. JVM的架构组成是怎样的?

JVM主要由**类加载器(ClassLoader)、运行时数据区(Runtime Data Area)、执行引擎(Execution Engine)和垃圾收集器(Garbage Collector)**组成。其中,类加载器负责加载Java类;运行时数据区包括堆、栈、方法区等内存区域;执行引擎负责执行字节码;垃圾收集器负责回收不再使用的内存。

  1. JVM的内存模型是怎样的?

JVM的内存模型主要包括堆、栈、方法区和本地方法栈等部分。堆是JVM所管理的最大一块内存区域,主要用于存放各种对象实例;栈是每个线程私有的一块内存区域,用于存储局部变量、操作数栈、动态链接、方法出口等信息;方法区用于存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;本地方法栈与栈类似,不过它是为Native方法服务的。

  1. 描述一下JVM加载class文件的原理机制?

JVM加载class文件的原理机制主要包括加载、链接和初始化三个阶段。加载阶段主要是通过类加载器将class文件加载到内存中,生成对应的Class对象;链接阶段包括验证、准备和解析三个步骤,主要是对字节码进行校验、为字段分配内存并设置初始值、将符号引用转换为直接引用等处理初始化阶段主要是对类的静态字段进行初始化。

  1. JVM的垃圾回收算法有哪些?

JVM的垃圾回收算法主要包括标记-清除算法、复制算法、标记-整理算法和分代收集算法。标记-清除算法是最基础的垃圾回收算法,它通过标记需要回收的对象并清除它们来回收内存;复制算法将内存分为两个区域,每次只使用其中一个区域,当该区域内存使用完时,将存活的对象复制到另一个区域中;标记-整理算法在标记-清除算法的基础上进行了优化,通过移动存活对象来消除内存碎片;分代收集算法根据对象存活周期的不同将内存划分为不同的区域,采用不同的垃圾回收算法进行回收。

  1. 你知道哪些垃圾收集器,各自的特点?

Java中的垃圾收集器主要包括Serial收集器、ParNew收集器、Parallel收集器、Cms收集器和G1收集器等。Serial收集器是单线程的,它在进行垃圾收集时会暂停所有用户线程;ParNew收集器是Serial收集器的多线程版本,它可以利用多个CPU核心进行垃圾收集;Parallel收集器也称为吞吐量优先收集器,它以并行的方式进行垃圾收集,并关注吞吐量;Cms收集器是一种以获取最短回收停顿时间为目标的收集器,它基于标记-清除算法实现;G1收集器是一种面向服务端应用的垃圾收集器,它将堆内存划分为多个独立的子区域,并可以预测停顿时间。

  1. 介绍一下JVM中的类加载机制,双亲委派模型是什么?

JVM中的类加载机制是指将Java类的字节码文件加载到内存中,并生成对应的Class对象的过程。类加载机制主要包括加载、链接和初始化三个阶段。在类加载过程中,JVM采用了双亲委派模型来保证类的唯一性和安全性。双亲委派模型是指当一个类加载器收到类加载请求时,它不会自己去加载这个类,而是将这个请求委派给父类加载器去完成。只有当父类加载器无法完成这个加载请求时,子类加载器才会尝试自己去加载。这样可以避免类的重复加载和一些安全问题。

  1. Java对象创建过程是怎样的?

Java对象的创建过程主要包括类加载、内存分配、初始化和返回对象引用等步骤。首先,JVM需要加载类的字节码文件并生成对应的Class对象;然后,在堆内存中为对象分配内存空间,并初始化对象的属性值和状态;最后,返回对象的引用给调用者。在对象创建过程中,JVM还会进行一些优化处理,如即时编译、逃逸分析等,以提高程序的执行效率。

  1. 描述一下Java内存模型(JMM)?

Java内存模型(JMM)是Java虚拟机规范中定义的一种内存模型,它描述了Java程序中线程之间的内存可见性和同步行为。JMM规定了所有的变量都存储在主内存中,而每个线程都有自己的工作内存。线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。JMM通过定义一系列的Happens-Before规则来保证多线程之间的内存可见性和有序性。

  1. 在工作中遇到jvm相关的问题?

A. Cms的触发参数配置太大,导致内存占比很高时未触发fgc
B. 默认GC配置是Parallel New + Old,需要通过参数配置才可使用ParNew + CMS 配置
C. 要配置gc日志和观察gc频率分析内存使用的合理性

  1. g1垃圾回收器什么情况下触发young gc,什么情况触发full gc?
  • G1的设计目标是尽量避免Full GC,因为它会导致较长的停顿时间。但在某些情况下,比如并发标记周期完成后没有足够的空闲Region来容纳晋升的对象,或者内存分配过快导致无法完成并发标记,就可能触发Full GC。另外,当晋升失败(Promotion Failure)或者疏散失败(Evacuation Failure)时,也可能触发Full GC。这时候G1会退化为Serial Old收集器来进行全堆的回收,导致较长时间的停顿。
  • 在G1(Garbage-First)垃圾回收器中,Young GC和Full GC的触发条件与堆内存分配、回收策略及运行时状态密切相关。以下是两者的触发场景及核心机制:

一、Young GC(年轻代垃圾回收)
触发条件
12. Eden区空间不足

  • 当应用程序分配新对象时,Eden区内存耗尽,无法满足新对象的分配请求。
  • G1会根据预设的停顿时间目标(-XX:MaxGCPauseMillis),动态调整Eden区的大小,但最终仍需触发Young GC。
  1. Survivor区晋升阈值
  • 虽然Young GC主要处理Eden区,但Survivor区对象的年龄(存活次数)达到阈值(默认15次,通过-XX:MaxTenuringThreshold配置)时,部分对象会晋升到老年代,间接影响Young GC的触发频率。
回收过程
  1. 标记存活对象:从GC Roots出发,标记Eden和Survivor区中存活的对象。
  2. 复制存活对象:将存活对象复制到新的Survivor区或直接晋升到老年代。
  3. 清空Eden/Survivor:回收完成后,Eden区和参与回收的Survivor区被清空。
配置参数
  • -XX:G1NewSizePercent:年轻代初始占比(默认堆的5%)
  • -XX:G1MaxNewSizePercent:年轻代最大占比(默认堆的60%)

二、Full GC(全堆垃圾回收)
触发条件

  1. 晋升失败(Promotion Failure)

    • Young GC过程中,Survivor区或老年代空间不足,无法容纳从Eden区晋升的对象。
    • 此时G1会尝试触发并发标记周期(Concurrent Marking Cycle)以回收老年代空间,若仍无法解决,则触发Full GC。
  2. 疏散失败(Evacuation Failure)

    • 在Mixed GC阶段(混合回收年轻代和部分老年代),老年代Region无法释放足够空间(如大对象或碎片化严重),导致对象无法被疏散(Evacuate),触发Full GC。
  3. 并发标记周期未完成

    • 如果并发标记周期(Concurrent Marking Cycle)未及时完成(如堆内存分配过快),G1可能被迫触发Full GC。
  4. 显式调用或系统资源不足

    • 调用System.gc()可能触发Full GC(依赖-XX:+ExplicitGCInvokesConcurrent配置)。
    • 操作系统内存不足时,JVM可能直接触发Full GC。
Full GC的特点
  • 单线程处理:G1的Full GC会退化为单线程的Serial Old收集器(Mark-Sweep-Compact算法),导致长时间停顿。
  • 全堆回收:同时处理年轻代和老年代,进行内存压缩以消除碎片。

三、触发对比

GC类型触发条件回收范围停顿时间
Young GCEden区满年轻代(Eden+Survivor)短(通常10-200ms)
Mixed GC老年代占用超过阈值(-XX:InitiatingHeapOccupancyPercent,默认45%)年轻代+部分老年代中等(依赖回收Region数)
Full GC晋升失败、疏散失败、并发标记未完成全堆长(秒级)

四、避免Full GC的优化建议

  1. 合理设置堆和分区大小

    • 增大堆内存(-Xms/-Xmx)或调整老年代触发阈值(-XX:InitiatingHeapOccupancyPercent,控制的是MIXED GC)。
  2. 减少对象晋升

    • 优化代码减少大对象分配,调整-XX:MaxTenuringThreshold降低晋升频率。
  3. 启用并行引用处理

    • 使用-XX:+ParallelRefProcEnabled加速引用对象的处理。
  4. 监控与调参

    • 通过GC日志(-Xlog:gc*)分析晋升失败原因,调整Survivor区比例(-XX:SurvivorRatio)。

五、关键诊断命令

# 查看GC原因(如触发Full GC的根源)
jstat -gccause <pid> 

# 分析GC日志中的晋升失败记录
grep "Promotion Failure" gc.log

# 检查老年代占用阈值
jinfo -flag InitiatingHeapOccupancyPercent <pid>

通过合理配置和监控,G1可在大多数场景下避免Full GC,保障低延迟和高吞吐量。若频繁触发Full GC,需结合日志分析具体原因并针对性优化。
11.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值