JVM 篇
1 什么是JVM
JVM 是 Java Virtual Machine 的缩写,是 Java 能够实现跨平台的根本原因,我们编写的 Java 代码,终究会被编译为字节码文件,然后运行于 JVM 虚拟机上, JVM 拥有多个平台的支持的版本,所以Java 能够跨平台(操作系统和不同的 CPU 架构)的原因是 JVM 拥有多个平台的版本的实现。
2 JVM 的组成
JVM 可以简单分为四个部分:
- 类加载器子系统
- 运行时数据区
- 执行引擎
- 本地方法接口
下面简单阐述下这四个部分的主要构成与功能:
- 类加载器子系统(Class Loader Subsystem)
-
作用:负责将字节码文件(.class)加载到 JVM 中,并完成验证、准备、解析、初始化等操作,最终形成可被 JVM 直接使用的类数据。
-
核心流程:
- 加载:通过类的全限定名获取字节流;
- 验证:确保字节码符合 JVM 规范(安全性校验);
- 准备:为类的静态变量分配内存并设置默认值;
- 解析:将符号引用转换为直接引用(如方法 / 字段的内存地址);
- 初始化:执行类构造器
<clinit>()方法(初始化静态变量和静态代码块)。
-
特点:采用 “双亲委派模型”,避免类的重复加载和安全问题。
- 运行时数据区(Runtime Data Area)
-
作用:这是 JVM 存储数据的区域,也是之前提到的 “内存区域” 的总称,是执行引擎运行的基础。
-
组成(按 Java 虚拟机规范):
-
程序计数器:记录当前线程执行的字节码指令地址(线程私有);
-
虚拟机栈:存储方法执行时的栈帧(局部变量、操作数栈等,线程私有);
-
本地方法栈:类似虚拟机栈,但为本地方法(如 C/C++ 方法)服务;
-
堆:存储对象实例和数组(线程共享,GC 主要区域);
-
方法区:存储类信息、常量、静态变量等(线程共享,JDK 8 后为元空间)。
-
- 执行引擎(Execution Engine)
-
作用:是 JVM 的 “心脏”,负责将字节码指令翻译为机器码并执行,是连接字节码和底层硬件的核心。
-
执行方式:
- 解释执行:逐条翻译字节码为机器码并立即执行(启动快,适合短程序);
- 即时编译(JIT 编译):将 “热点代码”(频繁执行的代码)编译为本地机器码并缓存,后续直接执行机器码(执行效率高,适合长运行程序);
- 混合模式:JVM 默认采用 “解释 + JIT” 混合执行,兼顾启动速度和运行效率。
-
核心组件:包括解释器、JIT 编译器(如 HotSpot 的 C1/C2 编译器)、垃圾回收器接口(配合堆内存管理)等。
- 本地方法接口(Native Method Interface, JNI)
-
作用:作为 JVM 与本地代码(如 C/C++)的桥梁,允许 Java 代码调用本地方法(通过
native关键字声明),扩展 JVM 的功能(如操作硬件、调用系统 API 等)。 -
配合组件:通常与 “本地方法栈” 协同工作,存储本地方法执行时的状态。
各个部分之间的协同关系:
- 类加载器将.class 文件加载到运行时数据区;
- 执行引擎从运行时数据区读取字节码,通过解释或编译方式执行;
- 执行过程中如需调用本地方法,通过 JNI 接口调用,使用本地方法栈存储状态;
- 运行时数据区的内存由垃圾回收器(属于执行引擎的辅助组件)自动管理,释放无用对象内存。
3 常见面试问题
类加载
类加载过程?
类加载机制?
双亲委派机制的优点?
什么时候需要打破双亲委派机制?
String 类的双亲委派机制可以打破吗?
运行时数据区
构成?
哪些会 OOM?
哪些是线程共享的?
JVM 不是自动回收垃圾吗,为什么还会 OOM?
垃圾回收
垃圾回收算法?
垃圾回收器?
什么时候会频繁触发 full GC?
G1?
CMS?
zgc?
生产问题
此部分参考 JavaGuide 的介绍,链接为: