JVM 的组成部分有什么
JVM(Java Virtual Machine)主要由以下几个核心组成部分构成:
1. 类加载器子系统 (Class Loader Subsystem):
-
职责: 负责加载类文件(.class 文件)到 JVM 中。
-
主要组件:
- 启动类加载器 (Bootstrap Class Loader):
- 负责加载 Java 核心类库(
<JAVA_HOME>/jre/lib
目录下的 rt.jar、resources.jar 等)。 - 是用 native code(C/C++)实现的,不是 Java 类。
- 它是所有类加载器的根。
- 负责加载 Java 核心类库(
- 扩展类加载器 (Extension Class Loader):
- 负责加载 Java 扩展类库(
<JAVA_HOME>/jre/lib/ext
目录下的 jar 包,或者由java.ext.dirs
系统属性指定的目录)。 - 是
sun.misc.Launcher$ExtClassLoader
的实例。
- 负责加载 Java 扩展类库(
- 应用程序类加载器 (Application Class Loader/System Class Loader):
- 负责加载应用程序的类(classpath 下的类)。
- 是
sun.misc.Launcher$AppClassLoader
的实例。 - 通常是默认的类加载器。
- 自定义类加载器 (User-Defined Class Loader):
- 开发者可以自定义类加载器,继承
java.lang.ClassLoader
类,实现特殊的类加载逻辑(例如,从网络加载类、从数据库加载类、对类进行加密解密等)。
- 开发者可以自定义类加载器,继承
- 启动类加载器 (Bootstrap Class Loader):
-
类加载机制:
- 双亲委派模型 (Parent Delegation Model):
- 当一个类加载器需要加载类时,它首先会委托给它的父类加载器去加载。
- 只有当父类加载器无法加载该类时(在其搜索范围内找不到该类),才由子类加载器尝试加载。
- 优点:
- 避免类的重复加载。
- 保证 Java 核心类库的安全性(防止用户自定义的类替换核心类)。
- 加载过程:
- 加载 (Loading): 查找并加载类的二进制数据(.class 文件)。
- 链接 (Linking):
- 验证 (Verification): 确保加载的类文件符合 JVM 规范,没有安全问题。
- 准备 (Preparation): 为类的静态变量分配内存,并设置默认初始值(零值)。
- 解析 (Resolution): 将类中的符号引用解析为直接引用(可选,可以延迟到运行时)。
- 初始化 (Initialization): 执行类的初始化代码(静态变量赋值、静态代码块)。
- 双亲委派模型 (Parent Delegation Model):
2. 运行时数据区 (Runtime Data Areas):
- 职责: JVM 在运行 Java 程序时管理的内存区域。
- 主要区域:
- 方法区 (Method Area):
- 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 所有线程共享。
- 在 HotSpot VM 中,方法区也被称为“非堆”(Non-Heap)或“永久代”(Permanent Generation,JDK 1.7 及之前)/“元空间”(Metaspace,JDK 1.8 及之后)。
- 运行时常量池 (Runtime Constant Pool): 方法区的一部分,存放编译期生成的各种字面量和符号引用。
- 堆 (Heap):
- 存储对象实例和数组。
- 所有线程共享。
- 是垃圾回收的主要区域。
- 可以划分为新生代(Young Generation)和老年代(Old Generation)。
- 新生代又可以划分为 Eden 区、Survivor from 区和 Survivor to 区。
- 虚拟机栈 (VM Stack):
- 存储方法调用的局部变量表、操作数栈、动态链接、方法出口等信息。
- 每个线程都有自己的虚拟机栈,栈的大小可以固定也可以动态扩展。
- 如果线程请求的栈深度大于虚拟机允许的深度,则抛出
StackOverflowError
。 - 如果虚拟机栈可以动态扩展,但无法申请到足够的内存,则抛出
OutOfMemoryError
。
- 本地方法栈 (Native Method Stack):
- 与虚拟机栈类似,但用于支持 native 方法(使用 C、C++ 等编写的方法)的执行。
- 每个线程都有自己的本地方法栈。
- 程序计数器 (Program Counter Register):
- 记录当前线程正在执行的字节码指令的地址(行号)。
- 每个线程都有自己的程序计数器。
- 是唯一一个在 Java 虚拟机规范中没有规定任何
OutOfMemoryError
情况的区域。
- 方法区 (Method Area):
3. 执行引擎 (Execution Engine):
- 职责: 负责执行 Java 字节码指令。
- 主要组件:
- 解释器 (Interpreter):
- 逐条解释执行字节码指令。
- 启动速度快,但执行速度慢。
- 即时编译器 (JIT Compiler):
- 将热点代码(经常执行的代码)编译为本地机器码,提高执行效率。
- 编译需要时间,但编译后的代码执行速度快。
- HotSpot VM 中的 JIT 编译器:
- Client Compiler (C1): 优化速度快,但优化程度较低。
- Server Compiler (C2): 优化速度慢,但优化程度较高。
- 分层编译 (Tiered Compilation): 根据程序的运行情况,选择不同的编译器进行优化(JDK 1.7 引入)。
- 垃圾回收器 (Garbage Collector):
- 负责自动回收不再使用的对象,释放内存。
- 不同的 JVM 实现有不同的垃圾回收器。
- 常见的垃圾回收器:
- Serial GC: 单线程垃圾回收器。
- Parallel GC: 多线程垃圾回收器。
- CMS GC (Concurrent Mark Sweep): 并发标记清除垃圾回收器。
- G1 GC (Garbage-First): 一种面向服务端应用的垃圾回收器。
- ZGC: 一种低延迟垃圾回收器.
- Shenandoah: 一种低延迟垃圾回收器.
- 本地方法接口 (JNI, Java Native Interface):
- 允许 Java 代码调用本地方法 (C/C++ 等编写的方法).
- 解释器 (Interpreter):
4. 本地库接口(Native Interface):
- 连接不同的编程语言, 为Java使用非Java代码编写的库提供支持.
JVM 架构图示:
+-----------------------------------------------------------------------------------+
| JVM |
+-----------------------------------------------------------------------------------+
| +---------------------+ +------------------------+ +---------------------+ |
| | 类加载器子系统 | | 运行时数据区 | | 执行引擎 | |
| | (Class Loader) | +------------------------+ +---------------------+ |
| +---------------------+ | +------------------+ | | +---------------+ | |
| | - 启动类加载器 | | | 方法区 (Method Area) | | | | 解释器 | | |
| | - 扩展类加载器 | | +------------------+ | | | (Interpreter) | | |
| | - 应用程序类加载器 | | | - 运行时常量池 | | | +---------------+ | |
| | - 自定义类加载器 | | +------------------+ | | +---------------+ | |
| +---------------------+ | +------------------+ | | | 即时编译器 | | |
| | | | 堆 (Heap) | | | | (JIT Compiler)| | |
| | | +------------------+ | | | - C1 (Client) | | |
| | | | - 新生代 | | | | - C2 (Server) | | |
| | | | - Eden | | | | - 分层编译 | | |
| | | | - Survivor | | | +---------------+ | |
| | | | - 老年代 | | | +---------------+ | |
| | | +------------------+ | | | 垃圾回收器 | | |
| | | +------------------+ | | | (GC) | | |
| | | | 虚拟机栈 (VM Stack) | | | +---------------+ | |
| | | +------------------+ | | | |
| | | +------------------+ | | +---------------+ | |
| | | | 本地方法栈 (Native) | | | |本地方法接口 | | |
| | | +------------------+ | | | (JNI) | | |
| | | +------------------+ | | +---------------+ | |
| | | | 程序计数器 (PC) | | | | |
| | | +------------------+ | | | |
| | +------------------------+ | | |
| | | | |
+-----------------------------------------------------------------------------------+
总结:
JVM 主要由类加载器子系统、运行时数据区、执行引擎、本地库接口等组成。
- 类加载器负责加载类文件。
- 运行时数据区负责管理内存。
- 执行引擎负责执行字节码指令和垃圾回收。
- 本地库接口负责连接其他语言。