执行引擎作用与工作过程
执行引擎:字节码到机器码的最后一公里
执行引擎是 JVM 的「最后一公里」——它把方法区中的字节码指令转换成当前机器的本地机器码,然后交给 CPU 执行。这是 Java「一次编译,到处运行」的最后一环。
执行引擎的位置
执行引擎位于 JVM 的核心位置,连接了运行时数据区和物理硬件:
┌─────────────────────────────────────────────┐
│ Java 源文件 │
│ │
│ javac 编译器 │
│ │
│ ▼ │
│ 字节码 (.class) │
│ │
│ Class Loader(类加载器) │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 运行时数据区 │ │
│ │ 堆 / 栈 / 方法区 │ │
│ └──────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 执行引擎 │ │
│ │ │ │
│ │ 解释器(Interpreter) │ │
│ │ JIT 编译器 │ │
│ │ GC 线程 │ │
│ └──────────┬────────────┘ │
│ │ │
│ ▼ │
│ 本地机器码 │
│ │ │
│ ▼ │
│ 操作系统 + 物理 CPU │
└─────────────────────────────────────────────┘执行引擎的两种执行方式
方式一:解释执行
解释器逐条读取字节码指令,翻译成机器码后立即执行。边翻译边执行,不需要预先编译。
字节码:iconst_1, iconst_2, iadd
↓ ↓ ↓
机器码 机器码 机器码
│ │ │
▼ ▼ ▼
执行 执行 执行优点:启动快(不需要编译),内存占用小。
缺点:每次执行都需要翻译,速度慢。
方式二:编译执行(JIT 编译)
Just-In-Time 编译器把热点字节码一次性编译成本地机器码并缓存,以后再执行时直接用编译后的代码。一次编译,多次执行。
字节码:iconst_1, iconst_2, iadd
│
│ (热点代码被 JIT 编译器捕获)
▼
一次性编译成本地机器码
│
│
▼
缓存到 Code Cache
│
│
▼
直接执行机器码(跳过解释)优点:执行速度快,接近原生代码。
缺点:编译需要时间(编译开销),占用额外内存。
两种方式的对比
| 维度 | 解释执行 | JIT 编译执行 |
|---|---|---|
| 启动速度 | 快(无需编译) | 慢(需要预热) |
| 执行速度 | 慢(每次翻译) | 快(编译后直接执行) |
| 内存占用 | 小 | 大(Code Cache) |
| 适用场景 | 短期程序、不常用代码 | 长期运行、热点代码 |
| 代表技术 | 解释器 | HotSpot JIT、C2 编译器 |
执行引擎的完整工作流程
Java 程序启动
│
▼
类加载(Class Loader)
│
▼
执行引擎初始化
│
├── 解释器启动(立即开始执行)
│
└── JIT 编译器就绪(后台编译热点代码)
│
▼
主线程开始执行字节码
│
├── 解释执行字节码
│
├── JIT 编译器后台编译热点代码
│ │
│ └── Code Cache 存储编译后代码
│
└── GC 线程并发执行
│
▼
程序结束 / JVM 退出解释器与 JIT 编译器并存
HotSpot VM 使用的是「解释器 + JIT 编译器」的混合模式:
字节码 → ┌──────────────────────────┐
│ 执行引擎 │
│ │
│ ┌────────────────────┐ │
│ │ 解释器 │ │
│ │ 逐条翻译,即时执行 │ │
│ └─────────┬──────────┘ │
│ │ │
│ │ (热点检测) │
│ ▼ │
│ ┌────────────────────┐ │
│ │ JIT 编译器 │ │
│ │ 编译热点,缓存代码 │ │
│ └─────────┬──────────┘ │
│ │ │
│ ▼ │
│ 本地机器码 │
│ (直接交给 CPU) │
└────────────┬───────────────┘
│
▼
CPU 执行为什么需要两者并存?答案很直接:
- 解释器负责快速启动,不需要等待编译
- JIT 编译器负责让长期运行的代码达到最高性能
两者的结合,让 JVM 既有良好的启动速度,又有出色的峰值性能。
执行引擎的内部组成
执行引擎内部
│
├── 解释器(Interpreter)
│ ├── 字节码解释器(bytecode interpreter)
│ └── 模板解释器(template interpreter)
│
├── JIT 编译器(JIT Compiler)
│ ├── C1 编译器(Client Compiler)
│ ├── C2 编译器(Server Compiler)
│ └── Graal 编译器
│
├── 热点探测器(HotSpot Detector)
│ ├── 方法调用计数器
│ └── 回边计数器
│
├── 代码缓存(Code Cache)
│ └── 存储编译后的本地机器码
│
└── GC 线程(与执行引擎并发运行)本节小结
执行引擎的核心要点:
| 关键点 | 说明 |
|---|---|
| 定位 | 字节码 → 本地机器码的转换器 |
| 解释执行 | 边翻译边执行,启动快但速度慢 |
| 编译执行 | 一次编译多次执行,速度快但有编译开销 |
| 混合模式 | 解释器 + JIT 编译器,取长补短 |
| 热点探测 | 识别高频调用的代码,只编译热点 |
理解执行引擎的工作原理,是理解 JVM 性能优化的入口。下一节,我们来看 编译 vs 解释运行(机器码/指令/汇编)。
