前言
前文介绍了数据库、中间件相关。本期我们继续学习Java特性的JVM。
JVM面试合集
- JVM的架构组成是怎样的?
JVM主要由**类加载器(ClassLoader)、运行时数据区(Runtime Data Area)、执行引擎(Execution Engine)和垃圾收集器(Garbage Collector)**组成。其中,类加载器负责加载Java类;运行时数据区包括堆、栈、方法区等内存区域;执行引擎负责执行字节码;垃圾收集器负责回收不再使用的内存。
- JVM的内存模型是怎样的?
JVM的内存模型主要包括堆、栈、方法区和本地方法栈等部分。堆是JVM所管理的最大一块内存区域,主要用于存放各种对象实例;栈是每个线程私有的一块内存区域,用于存储局部变量、操作数栈、动态链接、方法出口等信息;方法区用于存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;本地方法栈与栈类似,不过它是为Native方法服务的。
- 描述一下JVM加载class文件的原理机制?
JVM加载class文件的原理机制主要包括加载、链接和初始化三个阶段。加载阶段主要是通过类加载器将class文件加载到内存中,生成对应的Class对象;链接阶段包括验证、准备和解析三个步骤,主要是对字节码进行校验、为字段分配内存并设置初始值、将符号引用转换为直接引用等处理;初始化阶段主要是对类的静态字段进行初始化。
- JVM的垃圾回收算法有哪些?
JVM的垃圾回收算法主要包括标记-清除算法、复制算法、标记-整理算法和分代收集算法。标记-清除算法是最基础的垃圾回收算法,它通过标记需要回收的对象并清除它们来回收内存;复制算法将内存分为两个区域,每次只使用其中一个区域,当该区域内存使用完时,将存活的对象复制到另一个区域中;标记-整理算法在标记-清除算法的基础上进行了优化,通过移动存活对象来消除内存碎片;分代收集算法根据对象存活周期的不同将内存划分为不同的区域,采用不同的垃圾回收算法进行回收。
- 你知道哪些垃圾收集器,各自的特点?
Java中的垃圾收集器主要包括Serial收集器、ParNew收集器、Parallel收集器、Cms收集器和G1收集器等。Serial收集器是单线程的,它在进行垃圾收集时会暂停所有用户线程;ParNew收集器是Serial收集器的多线程版本,它可以利用多个CPU核心进行垃圾收集;Parallel收集器也称为吞吐量优先收集器,它以并行的方式进行垃圾收集,并关注吞吐量;Cms收集器是一种以获取最短回收停顿时间为目标的收集器,它基于标记-清除算法实现;G1收集器是一种面向服务端应用的垃圾收集器,它将堆内存划分为多个独立的子区域,并可以预测停顿时间。
- 介绍一下JVM中的类加载机制,双亲委派模型是什么?
JVM中的类加载机制是指将Java类的字节码文件加载到内存中,并生成对应的Class对象的过程。类加载机制主要包括加载、链接和初始化三个阶段。在类加载过程中,JVM采用了双亲委派模型来保证类的唯一性和安全性。双亲委派模型是指当一个类加载器收到类加载请求时,它不会自己去加载这个类,而是将这个请求委派给父类加载器去完成。只有当父类加载器无法完成这个加载请求时,子类加载器才会尝试自己去加载。这样可以避免类的重复加载和一些安全问题。
- Java对象创建过程是怎样的?
Java对象的创建过程主要包括类加载、内存分配、初始化和返回对象引用等步骤。首先,JVM需要加载类的字节码文件并生成对应的Class对象;然后,在堆内存中为对象分配内存空间,并初始化对象的属性值和状态;最后,返回对象的引用给调用者。在对象创建过程中,JVM还会进行一些优化处理,如即时编译、逃逸分析等,以提高程序的执行效率。
- 描述一下Java内存模型(JMM)?
Java内存模型(JMM)是Java虚拟机规范中定义的一种内存模型,它描述了Java程序中线程之间的内存可见性和同步行为。JMM规定了所有的变量都存储在主内存中,而每个线程都有自己的工作内存。线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。JMM通过定义一系列的Happens-Before规则来保证多线程之间的内存可见性和有序性。
- 在工作中遇到jvm相关的问题?
A. Cms的触发参数配置太大,导致内存占比很高时未触发fgc
B. 默认GC配置是Parallel New + Old,需要通过参数配置才可使用ParNew + CMS 配置
C. 要配置gc日志和观察gc频率分析内存使用的合理性
- 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。
- Survivor区晋升阈值
- 虽然Young GC主要处理Eden区,但Survivor区对象的年龄(存活次数)达到阈值(默认15次,通过
-XX:MaxTenuringThreshold配置)时,部分对象会晋升到老年代,间接影响Young GC的触发频率。
回收过程
- 标记存活对象:从GC Roots出发,标记Eden和Survivor区中存活的对象。
- 复制存活对象:将存活对象复制到新的Survivor区或直接晋升到老年代。
- 清空Eden/Survivor:回收完成后,Eden区和参与回收的Survivor区被清空。
配置参数
-XX:G1NewSizePercent:年轻代初始占比(默认堆的5%)-XX:G1MaxNewSizePercent:年轻代最大占比(默认堆的60%)
二、Full GC(全堆垃圾回收)
触发条件
-
晋升失败(Promotion Failure)
- Young GC过程中,Survivor区或老年代空间不足,无法容纳从Eden区晋升的对象。
- 此时G1会尝试触发并发标记周期(Concurrent Marking Cycle)以回收老年代空间,若仍无法解决,则触发Full GC。
-
疏散失败(Evacuation Failure)
- 在Mixed GC阶段(混合回收年轻代和部分老年代),老年代Region无法释放足够空间(如大对象或碎片化严重),导致对象无法被疏散(Evacuate),触发Full GC。
-
并发标记周期未完成
- 如果并发标记周期(Concurrent Marking Cycle)未及时完成(如堆内存分配过快),G1可能被迫触发Full GC。
-
显式调用或系统资源不足
- 调用
System.gc()可能触发Full GC(依赖-XX:+ExplicitGCInvokesConcurrent配置)。 - 操作系统内存不足时,JVM可能直接触发Full GC。
- 调用
Full GC的特点
- 单线程处理:G1的Full GC会退化为单线程的Serial Old收集器(
Mark-Sweep-Compact算法),导致长时间停顿。 - 全堆回收:同时处理年轻代和老年代,进行内存压缩以消除碎片。
三、触发对比
| GC类型 | 触发条件 | 回收范围 | 停顿时间 |
|---|---|---|---|
| Young GC | Eden区满 | 年轻代(Eden+Survivor) | 短(通常10-200ms) |
| Mixed GC | 老年代占用超过阈值(-XX:InitiatingHeapOccupancyPercent,默认45%) | 年轻代+部分老年代 | 中等(依赖回收Region数) |
| Full GC | 晋升失败、疏散失败、并发标记未完成 | 全堆 | 长(秒级) |
四、避免Full GC的优化建议
-
合理设置堆和分区大小
- 增大堆内存(
-Xms/-Xmx)或调整老年代触发阈值(-XX:InitiatingHeapOccupancyPercent,控制的是MIXED GC)。
- 增大堆内存(
-
减少对象晋升
- 优化代码减少大对象分配,调整
-XX:MaxTenuringThreshold降低晋升频率。
- 优化代码减少大对象分配,调整
-
启用并行引用处理
- 使用
-XX:+ParallelRefProcEnabled加速引用对象的处理。
- 使用
-
监控与调参
- 通过GC日志(
-Xlog:gc*)分析晋升失败原因,调整Survivor区比例(-XX:SurvivorRatio)。
- 通过GC日志(
五、关键诊断命令
# 查看GC原因(如触发Full GC的根源)
jstat -gccause <pid>
# 分析GC日志中的晋升失败记录
grep "Promotion Failure" gc.log
# 检查老年代占用阈值
jinfo -flag InitiatingHeapOccupancyPercent <pid>
通过合理配置和监控,G1可在大多数场景下避免Full GC,保障低延迟和高吞吐量。若频繁触发Full GC,需结合日志分析具体原因并针对性优化。
11.
本文详细阐述了Java虚拟机JVM的架构组成,包括类加载器、运行时数据区、执行引擎和垃圾收集器。此外,还讲解了内存模型、类加载原理、垃圾回收算法以及常见问题如Cms收集器的配置和内存优化。
86万+

被折叠的 条评论
为什么被折叠?



