JVM 结构概述
JVM 的核心结构可以分为以下几个部分:
- 类加载子系统(Class Loader Subsystem)
- 运行时数据区(Runtime Data Areas)
- 执行引擎(Execution Engine)
- 本地方法接口(Native Method Interface)
- 本地方法库(Native Libraries)
下面我们分别从这些部分来对比 JDK 8 和 JDK 17 的 JVM 结构。
1. 类加载子系统(Class Loader Subsystem)
类加载子系统负责加载 Java 类文件(.class
文件)到 JVM 中。
JDK 8 和 JDK 17 的类加载机制
- 类加载器层次结构:
- Bootstrap ClassLoader:加载核心 Java 类(如
java.lang.*
)。
- Extension ClassLoader:加载扩展类(
jre/lib/ext
目录下的类)。
- Application ClassLoader:加载应用程序类路径(Classpath)下的类。
- Custom ClassLoader:用户自定义的类加载器。
- 双亲委派模型:
- 类加载器在加载类时,首先委托给父类加载器,只有在父类加载器无法加载时,才自己加载。
- JDK 8 和 JDK 17 都遵循双亲委派模型。
- 变化:
- JDK 9 引入了模块化系统(Jigsaw[音:急个啥]),类加载机制有所调整,但 JDK 17 仍然兼容 JDK 8 的类加载机制。
2. 运行时数据区(Runtime Data Areas)
运行时数据区是 JVM 内存管理的核心部分,主要包括以下几个区域:
JDK 8 的运行时数据区
- 方法区(Method Area) :
- 存储类信息、常量、静态变量等。
- 在 JDK 8 中,方法区的实现是 永久代(PermGen) 。
- 堆(Heap) :
- 存储对象实例和数组。
- 分为年轻代(Young Generation)和老年代(Old Generation)。
- 年轻代进一步分为 Eden 区、Survivor 区(From 和 To)。
- 栈(Stack) :
- 每个线程私有的栈,存储局部变量和方法调用。
- 包括局部变量表、操作数栈、动态链接、方法返回地址等。
- 程序计数器(Program Counter Register) :
- 本地方法栈(Native Method Stack) :
- 用于执行本地方法(Native Methods)。
JDK 17 的运行时数据区
- 元空间(Metaspace) :
- 取代了 JDK 8 中的永久代(PermGen)。
- 存储类信息、常量、静态变量等。
- 元空间使用本地内存(Native Memory),不再受 JVM 堆内存限制。
- 堆(Heap) :
- 与 JDK 8 类似,分为年轻代和老年代。
- 支持更大的堆内存(如 ZGC 和 Shenandoah GC 支持 TB 级别的堆)。
- 栈(Stack) :
- 程序计数器(Program Counter Register) :
- 本地方法栈(Native Method Stack) :
变化:
- 永久代被元空间取代:
- JDK 8 的永久代容易导致
OutOfMemoryError: PermGen space
错误。
- JDK 17 使用元空间,动态调整内存大小,避免了永久代的限制。
3. 执行引擎(Execution Engine)
执行引擎负责执行字节码指令。
JDK 8 和 JDK 17 的执行引擎
- 解释器(Interpreter) :
- 即时编译器(JIT Compiler) :
- 将热点代码(HotSpot)编译为本地机器码,提高执行效率。
- JDK 8 和 JDK 17 都使用****C1(Client Compiler) 和 C2(Server Compiler) 。
- 垃圾回收器(Garbage Collector) :
- JDK 8 默认使用 Parallel GC。
- JDK 17 默认使用 G1 GC,并引入了 ZGC 和 Shenandoah GC。
变化:
- JDK 17 对 JIT 编译器进行了优化,提升了编译效率。
- JDK 17 引入了新的垃圾回收器(如 ZGC 和 Shenandoah GC),支持更低延迟和更大堆内存。
4. 本地方法接口(Native Method Interface)
- 提供 Java 代码调用本地方法(如 C/C++ 代码)的能力。
- JDK 8 和 JDK 17 的本地方法接口基本一致。
5. 本地方法库(Native Libraries)
- 包含 JVM 所需的本地库(如线程、网络、文件系统等)。
- JDK 17 对本地方法库进行了优化,提升了性能和兼容性。
JDK 8 和 JDK 17 的 JVM 结构对比总结
组件 | JDK 8 | JDK 17 |
类加载子系统 | 双亲委派模型 | 双亲委派模型,支持模块化系统 |
方法区 | 永久代(PermGen) | 元空间(Metaspace) |
堆内存 | 年轻代 + 老年代 | 年轻代 + 老年代,支持更大堆内存 |
垃圾回收器 | 默认 Parallel GC | 默认 G1 GC,支持 ZGC、Shenandoah |
执行引擎 | C1 和 C2 编译器 | 优化后的 C1 和 C2 编译器 |
本地方法接口 | 支持本地方法调用 | 支持本地方法调用 |
本地方法库 | 基础本地库 | 优化后的本地库 |
总结
- JDK 8 的 JVM 结构以永久代和 Parallel GC 为特点,适合传统的 Java 应用。
- JDK 17 的 JVM 结构引入了元空间、G1 GC、ZGC 等新技术,更适合现代应用(如低延迟、大内存场景)。
- JDK 17 在性能、内存管理和垃圾回收方面有显著改进,推荐在新项目中使用。