JVM 的组成
JVM(Java Virtual Machine)是 Java 的核心组件,负责执行 Java 字节码程序。以下是 JVM 的主要组成部分:
1. 类加载子系统(Class Loader Subsystem)
作用:负责加载 .class 文件到 JVM,将其转换为 JVM 能识别的内部数据结构。
组成:
Bootstrap ClassLoader(引导类加载器):加载 JDK 核心类库(rt.jar)。
Extension ClassLoader(扩展类加载器):加载扩展库(lib/ext 中的类)。
Application ClassLoader(应用类加载器):加载应用程序的类路径中的类。
过程:
加载(Loading):通过文件、网络等方式加载 .class 文件。
验证(Verification):确保字节码文件的合法性和安全性。
准备(Preparation):为类的静态字段分配内存并赋默认值。
解析(Resolution):将符号引用转换为直接引用。
初始化(Initialization):执行类的静态代码块或初始化静态字段。
2. 运行时数据区(Runtime Data Area)
JVM 为执行 Java 程序分配的内存区域,包括以下部分:
a. 方法区(Method Area)
存储:
类元信息(类名、方法名、字段名等)。
静态变量。
运行时常量池。
特点:
是线程共享的。
在 JDK 8 以前对应于永久代(PermGen),在 JDK 8 后改为元空间(Metaspace)。
b. 堆区(Heap Area)
存储:
所有对象实例和数组。
特点:
是线程共享的。
垃圾回收(GC)主要针对堆区。
通常分为年轻代(Young Generation)、老年代(Old Generation)和永久代(PermGen,JDK 8 以后移除)。
c. Java 栈区(Java Stack Area)
存储:
方法调用的局部变量。
每个方法调用对应一个栈帧(Frame)。
特点:
是线程私有的。
方法调用结束后,栈帧会弹出,内存自动回收。
d. 程序计数器(Program Counter Register)
功能:
记录当前线程正在执行的字节码指令地址。
特点:
是线程私有的。
e. 本地方法栈(Native Method Stack)
功能:
为本地方法(非 Java 方法,如通过 JNI 调用的 C 或 C++ 方法)服务。
特点:
是线程私有的。
3. 执行引擎(Execution Engine)
作用:负责执行字节码。
组成:
解释器(Interpreter):逐条解释字节码并执行。
即时编译器(JIT Compiler):
热点代码(频繁执行的代码)会被 JIT 编译为机器码,以提高执行速度。
包括 C1(Client Compiler,快速编译)和 C2(Server Compiler,高性能优化)。
垃圾回收器(Garbage Collector,GC):
自动回收不再使用的对象所占的内存。
4. 本地方法接口(Native Interface)
作用:提供调用非 Java 代码(如 C、C++)的接口。
工作机制:
通过 JNI(Java Native Interface)调用本地方法。
实现与底层操作系统和硬件的交互,如文件系统、网络操作。
5. JVM 内存模型(Java Memory Model, JMM)
作用:定义线程如何交互以及如何访问内存。
主要内容:
主内存(Main Memory):所有线程共享的内存区域。
工作内存(Working Memory):每个线程独立的内存区域,用于存储线程私有的数据。
可见性:规定线程对共享变量的修改如何被其他线程看到。
原子性:确保基本操作的不可分割性。
有序性:保证程序的执行顺序符合预期。
6. JVM 垃圾回收子系统
作用:自动管理内存,回收不再使用的对象。
常用算法:
标记-清除算法。
标记-压缩算法。
复制算法。
分代收集算法。
常见垃圾回收器:
Serial GC、Parallel GC、CMS、G1 GC、ZGC、Shenandoah 等。
JVM 的工作原理
加载类:通过类加载子系统加载 .class 文件。
分配内存:在堆、栈等区域分配对象和方法的内存。
执行字节码:通过执行引擎逐条解释或即时编译代码并运行。
垃圾回收:定期清理无用的对象,释放内存。
总结
JVM 的组成模块紧密协作,为 Java 程序提供了一个高效、安全、跨平台的运行环境。每个部分都有其特定功能,共同构成了完整的 JVM。