目录
[一. 关键概述](#一. 关键概述)
[二. 核心功能](#二. 核心功能)
[三. 组成架构](#三. 组成架构)
[1. 类加载子系统 (ClassLoader)](#1. 类加载子系统 (ClassLoader))
[2. 运行时数据区 (Runtime Data Areas)](#2. 运行时数据区 (Runtime Data Areas))
[3. 执行引擎 (Execution Engine)](#3. 执行引擎 (Execution Engine))
[四. 类加载机制](#四. 类加载机制)
[五. 垃圾回收 (GC)](#五. 垃圾回收 (GC))
[六. JIT 编译器 (Just-In-Time)](#六. JIT 编译器 (Just-In-Time))
[七. 调优参数示例](#七. 调优参数示例)
[八. 常见问题与工具](#八. 常见问题与工具)
[九. 与 JDK/JRE 的关系](#九. 与 JDK/JRE 的关系)
[十. 调优与监控](#十. 调优与监控)
[十一. 常见实现](#十一. 常见实现)
[十二. 简单示例](#十二. 简单示例)
[十三. 总结归纳](#十三. 总结归纳)
一. 关键概述
Java 虚拟机(JVM,Java Virtual Machine)是 Java 平台的核心组成部分,负责将编译后的字节码(`.class` 文件)解释或编译为机器码,并在不同操作系统上实现"一次编写,到处运行"(Write Once, Run Anywhere)的跨平台特性。
二. 核心功能
-
**跨平台执行:**将字节码翻译成不同操作系统的本地机器指令。
-
**内存管理:**自动分配/回收内存(堆、栈等),避免手动管理错误。
-
**垃圾回收 (GC):**自动回收无用的对象内存。
-
**字节码执行:**通过解释器或 JIT 编译器执行字节码。
三. 组成架构
1. 类加载子系统 (ClassLoader)
组件 | 功能描述 | 关键特性 |
---|---|---|
Bootstrap ClassLoader | 加载 JAVA_HOME/lib 的核心类库(如 rt.jar ) |
由 C++ 实现,JVM 自身的一部分 |
Extension ClassLoader | 加载 JAVA_HOME/lib/ext 目录的扩展类库 |
继承自 URLClassLoader ,父加载器为 Bootstrap |
Application ClassLoader | 加载用户类路径(classpath)的类 | 默认线程上下文类加载器,父加载器为 Extension |
双亲委派模型 | 加载类时优先委派父类加载器处理 | 避免核心类被篡改(如自定义 java.lang.String ),确保安全性和类唯一性 |
2. 运行时数据区 (Runtime Data Areas)
内存区域 | 存储内容 | 特性 |
---|---|---|
方法区 (Method Area) | 类元数据(类名、字段、方法)、常量池、静态变量 | JDK 8+ 由元空间 (Metaspace) 实现,使用本地内存,替代永久代(PermGen) |
堆 (Heap) | 对象实例和数组 | 垃圾回收主区域 ,分为: - 新生代(Eden + Survivor From/To) - 老年代 |
虚拟机栈 (JVM Stack) | 每个线程私有,存储栈帧(局部变量表、操作数栈、动态链接、方法出口) | 方法调用压栈,返回弹栈;可能抛出 StackOverflowError |
本地方法栈 | 服务于 Native 方法(如 JNI 调用的 C/C++ 代码) | 与虚拟机栈类似,但针对本地方法 |
程序计数器 (PC Register) | 记录当前线程执行的字节码指令地址 | 唯一不会发生 OOM 的区域,线程私有 |
3. 执行引擎 (Execution Engine)
组件 | 功能描述 | 关键实现 |
---|---|---|
解释器 (Interpreter) | 逐行解释字节码为机器码执行 | 启动速度快,但运行时效率低 |
JIT 编译器 | 将热点代码(高频方法/循环)编译为本地机器码 | HotSpot 使用分层编译: - C1 编译器(客户端,快速优化) - C2 编译器(服务端,深度优化) |
垃圾回收器 (GC) | 自动回收无引用对象的内存 | 主流算法与收集器 : - 新生代:复制算法 (Parallel Scavenge) - 老年代:标记-清除/整理 (CMS) - G1 GC (JDK9+ 默认):区域化分代 + 可预测停顿 - ZGC(JDK11+):低延迟(<10ms)、TB 级 |
核心关系总结
- 类加载 → 运行时数据区:
ClassLoader
加载的类元数据存储于方法区,对象实例分配在堆中。
- 执行引擎 → 运行时数据区:
解释器/JIT 执行栈中方法的字节码;GC 管理堆内存的回收。
- 线程私有区域:
每个线程独立拥有:虚拟机栈、本地方法栈、程序计数器。
四. 类加载机制
类加载分三个阶段:
1. **加载 (Loading)**
-
通过类加载器(`ClassLoader`)加载 `.class` 文件到内存。
-
类加载器层级:
-
**Bootstrap ClassLoader**(加载核心库如 `rt.jar`)
-
**Extension ClassLoader**(加载扩展库)
-
**Application ClassLoader**(加载用户类路径)
-
**自定义 ClassLoader**(用户扩展)。
2. **链接 (Linking)** -
验证字节码合法性 → 准备(为静态变量分配内存)→ 解析(符号引用转直接引用)。
3. **初始化 (Initialization)** -
执行静态代码块和静态变量赋值(如 `static int x = 10;`)。
五. 垃圾回收 (GC)
- **回收对象**: 无引用指向的对象(如超出作用域的局部变量)。
- **GC 算法**:
-
**分代收集**:堆分为 **新生代 (Young)** 和 **老年代 (Old)**。
-
新生代:使用 **复制算法**(Eden + Survivor 区)。
-
老年代:使用 **标记-清除** 或 **标记-整理** 算法。
-
**垃圾收集器**:
-
**Serial GC**:单线程,适合小应用。
-
**Parallel GC**(默认):多线程,吞吐量优先。
-
**CMS** / **G1 GC**:低延迟,减少 STW(Stop-The-World)时间。
-
**ZGC** / **Shenandoah**(JDK 15+):超低延迟(<10ms)。
六. JIT 编译器 (Just-In-Time)
-
**热点代码优化**:频繁执行的字节码会被编译成本地机器码(如循环、高频方法)。
-
**解释器 vs JIT**:解释器逐行执行字节码(启动快);JIT 编译后执行(运行快)。
七. 调优参数示例
堆内存设置
-Xms512m # 初始堆大小(默认物理内存 1/64)
-Xmx1024m # 最大堆大小(默认物理内存 1/4)
-XX:NewRatio=2 # 老年代:新生代 = 2:1
-XX:SurvivorRatio=8 # Eden:Survivor = 8:1
垃圾回收器选择
-XX:+UseG1GC # 启用 G1 收集器
-XX:+UseConcMarkSweepGC # 启用 CMS 收集器
元空间设置(JDK 8+)
-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m
八. 常见问题与工具
- **内存泄漏**: 对象被意外保留引用(如静态集合类持续增长)。
- **OOM (OutOfMemoryError)**: 堆/元空间不足。
- **诊断工具**:
-
**jconsole** / **VisualVM**:图形化监控堆、线程、类加载。
-
**jstack**:分析线程堆栈(死锁检测)。
-
**jmap**:导出堆内存快照(配合 **MAT** 工具分析内存泄漏)。
-
**jstat**:监控 GC 状态(`jstat -gcutil <pid> 1000`)。
九. 与 JDK/JRE 的关系
-
**JDK (Java Development Kit)**:开发工具包(含 JRE + 编译器 `javac`)。
-
**JRE (Java Runtime Environment)**:运行环境(含 JVM + 基础库)。
-
**JVM**:执行引擎,是 JRE 的子集。
十. 调优与监控
- **常用参数**:
-
堆大小:`-Xms`(初始堆)、`-Xmx`(最大堆)。
-
新生代比例:`-XX:NewRatio`。
-
GC 日志:`-Xlog:gc*`(JDK 9+)。
-
元空间:`-XX:MaxMetaspaceSize`。
- **监控工具**: -
**JVisualVM**:可视化监控线程、堆、GC。
-
**JConsole**:实时查看内存、线程、类加载。
-
**jstack**:查看线程堆栈(定位死锁)。
-
**jmap**:生成堆转储(`jmap -dump` 分析内存泄漏)。
十一. 常见实现
-
**HotSpot**(Oracle/OpenJDK 默认):支持 JIT 和多种 GC。
-
**OpenJ9**(IBM):低内存占用,适合云原生。
-
**GraalVM**:多语言支持(Java/Python/JS),原生镜像(AOT 编译)。
十二. 简单示例
java
// 内存泄漏示例:静态集合持有对象引用
public class MemoryLeak {
private static final List<Object> list = new ArrayList<>();
public void addData() {
while (true) {
list.add(new byte[1024 * 1024]); // 持续占用内存
}
}
}
排查步骤:
-
使用 `jmap -dump:format=b,file=heap.hprof <pid>` 生成堆转储。
-
通过 MAT 或 VisualVM 分析泄漏路径(如 `list` 持续增长)。
十三. 总结归纳
JVM 是 Java 生态的基石,理解其内存模型、类加载、GC 机制是优化性能的关键。掌握 JVM 调优和诊断工具,能有效解决内存溢出、高延迟等问题。JVM 通过抽象操作系统差异、自动化内存管理和高效的执行引擎,成为 Java 高性能和跨平台能力的基石。理解其原理和调优技巧,是 Java 开发者进阶的必经之路。