Java 虚拟机(JVM, Java Virtual Machine)是 Java 技术体系的核心。它负责运行 Java 字节码,是 Java 实现"一次编写,到处运行"的基础。JVM 主要提供以下几个核心功能:
- 类加载机制
- 内存管理机制
- 垃圾回收机制
- 字节码执行引擎
本文重点围绕 类加载、内存管理、垃圾回收与垃圾收集器 进行系统讲解。
1. 类加载机制(Class Loading)
JVM 在运行期间需要将 .class
文件加载到内存,这一过程由类加载子系统负责,分为以下几个阶段:
类加载的五个阶段:
阶段 | 说明 |
---|---|
加载(Loading) | 通过类的全限定名获取字节流,并生成 Class 对象。 |
连接(Linking) | 包括验证、准备、解析三个子阶段。 |
验证(Verification) | 确保字节码格式正确、合法、不会破坏虚拟机。 |
准备(Preparation) | 为类的静态变量分配内存并设置初始值(默认值)。 |
解析(Resolution) | 将常量池中的符号引用替换为直接引用。 |
初始化(Initialization) | 执行类构造器 <clinit> 方法,初始化静态变量。 |
类加载器(ClassLoader)
Java 提供了三种主要的类加载器:
- Bootstrap ClassLoader(引导类加载器) :C++ 实现,加载
rt.jar
- Extension ClassLoader(扩展类加载器) :加载
ext
目录下的类 - Application ClassLoader(应用类加载器) :加载
classpath
下的类
2. Java 内存管理(Memory Structure)
JVM 在运行时将内存划分为几个逻辑区域,用于存储不同类型的数据:
内存结构总览
区域 | 线程共享 | 说明 |
---|---|---|
方法区(Method Area) | 是 | 存放类信息、常量、静态变量等,JDK 8 后称为 metaspace |
堆(Heap) | 是 | 所有对象实例和数组分配的地方,GC 的主要工作区域 |
虚拟机栈(JVM Stack) | 否 | 每个线程一个栈,存储栈帧,用于方法调用 |
本地方法栈(Native Method Stack) | 否 | 调用 Native 方法时使用 |
程序计数器(PC Register) | 否 | 当前线程所执行字节码的行号指示器 |
堆内存结构(重点)
JVM 堆通常分为以下几个区域:
-
Young Generation(新生代)
- Eden 区:大部分对象在此创建。
- Survivor 区:两个区(S0、S1)轮流使用,存活对象在其中复制移动。
-
Old Generation(老年代)
- 存放长生命周期对象、晋升的新生代对象。
-
Metaspace(元空间)
- JDK 8 后替代永久代,使用本地内存而非堆内存。
3. 垃圾回收算法(GC Algorithm)
JVM 使用 GC 算法自动回收内存,主要算法如下:
常见 GC 算法对比
算法 | 原理 | 适用区域 | 优点 | 缺点 |
---|---|---|---|---|
标记-清除(Mark-Sweep) | 标记活对象,清除未被标记对象 | 老年代 | 实现简单 | 空间碎片问题严重 |
复制算法(Copying) | 活对象复制到新区域,旧区域清空 | 新生代 | 无碎片,效率高 | 空间浪费(只用一半) |
标记-整理(Mark-Compact) | 标记后让所有活对象移动到一起 | 老年代 | 无碎片 | 移动对象成本高 |
分代收集算法 | 新生代用复制,老年代用标记整理 | 新生+老年代 | 各取所长 | 实现复杂 |
4. 垃圾收集器(GC Collector)
JVM 提供了多种垃圾收集器,不同收集器适用于不同场景。以下是主流收集器及其特性:
新生代收集器
收集器 | 特性 | 备注 |
---|---|---|
Serial | 单线程,简单高效 | 适合单核 CPU,小型应用 |
ParNew | 多线程版本 Serial | 常与 CMS 搭配使用 |
Parallel Scavenge | 多线程,注重吞吐量 | 吞吐量优先,适用于后台计算 |
老年代收集器
收集器 | 特性 | 备注 |
---|---|---|
Serial Old | 单线程标记整理 | 与 Serial、CMS 搭配 |
Parallel Old | 多线程标记整理 | Parallel Scavenge 的老年代版本 |
CMS(Concurrent Mark-Sweep) | 并发回收,低延迟 | 停顿少,易产生碎片,已被废弃(JDK 14) |
G1(Garbage First) | 分区回收,预测性好 | JDK 9 默认收集器,适用于大内存低延迟场景 |
ZGC(Z Garbage Collector) | 超低延迟(<10ms) | JDK 11 引入,支持 TB 级堆 |
Shenandoah | 并发压缩 | JDK 12 引入,RedHat 主导,适合低延迟场景 |
垃圾收集器对比
收集器 | 吞吐量 | 停顿时间 | 并发能力 | 是否碎片整理 | 特点 |
---|---|---|---|---|---|
CMS | 中等 | 低 | 并发标记清理 | 无 | 低延迟,回收碎片难 |
G1 | 高 | 可预测 | 并发 | 有 | Region + 并发整理 |
ZGC | 中 | 超低(<10ms) | 高 | 有 | 支持超大堆,GC 与应用线程并发运行 |
Shenandoah | 中 | 超低 | 高 | 有 | GC 与应用并发,适合响应敏感型场景 |
面试高频考点总结
问题 | 答案要点 |
---|---|
JVM 有哪些内存区域? | 堆、方法区、虚拟机栈、本地方法栈、程序计数器 |
新生代与老年代的区别? | 新生代生命周期短,采用复制算法;老年代生命周期长,用标记整理 |
GC 有哪些算法? | 标记清除、复制、标记整理、分代收集 |
CMS 的优缺点? | 并发低停顿,容易碎片,回收失败可能 Full GC |
G1 与 CMS 对比? | G1 具备 Region 机制与预测回收,解决碎片问题,更适合大堆 |
ZGC 的优势? | 超低延迟,支持大内存,GC 过程与应用线程几乎完全并发 |