Skip to content

07 - 执行引擎与 JIT

定位: 执行引擎是 JVM 的"CPU"——将字节码转换为机器码并执行。解释执行保证快速启动,JIT 编译保证峰值性能。 面试高频度: ⭐⭐⭐⭐⭐

一、执行引擎在 JVM 体系中的位置

类加载器将 Class 文件加载到内存后,执行引擎负责真正执行这些代码

┌─────────────────────────────────────────────────────────────────────────┐
│                      JVM 整体架构                                          │
│                                                                         │
│  源码 ─→ 编译 ─→ Class文件 ─→ 类加载 ─→ 运行时数据区 ─→ 执行引擎 ─→ 机器码   │
│                                      │                  │                │
│                                      ▼                  ▼                │
│                                ┌──────────┐      ┌──────────┐           │
│                                │ 方法区     │      │ 解释器    │           │
│                                │ 堆        │      │ C1 编译器 │           │
│                                │ 栈        │      │ C2 编译器 │           │
│                                └──────────┘      └──────────┘           │
│                                                                         │
│  ~~~~~ 静态部分 (编译期+加载期) ~~~~~      ~~~~~ 动态部分 (运行期) ~~~~~    │
└─────────────────────────────────────────────────────────────────────────┘
  • 向上: 从运行时数据区读取字节码指令(方法区中的 Code 属性)
  • 向下: 将字节码翻译为机器码,在目标 CPU 上执行
  • 横向: 与运行时数据区双向交互——栈帧操作、堆对象分配、方法调用

二、子专题导航

#主题面试频率核心内容
**解释执行与编译执行**混合执行模式⭐⭐⭐⭐解释器 vs 编译器、热点检测、OSR、CompileThreshold
**C1与C2编译器与分层编译**JIT 编译器⭐⭐⭐⭐⭐C1 vs C2 优化管线、5 级分层编译、去优化 (Deopt)
**方法内联和逃逸分析**核心 JIT 优化⭐⭐⭐⭐⭐方法内联(最重要优化)、逃逸分析、虚调用优化
**锁消除与标量替换**高级 JIT 优化⭐⭐⭐⭐锁消除、标量替换、StringBuffer 案例、条件分析
**JITWatch使用**JIT 分析工具⭐⭐⭐JIT 日志生成、TriView、内联报告、性能瓶颈定位

三、核心概念全景

┌──────────────────────────────────────────────────────────────────────────┐
│                      JIT 编译全景流程图                                      │
│                                                                          │
│  字节码 (bytecode)                                                        │
│      │                                                                   │
│      ▼                                                                   │
│  ┌──────────────────────┐                                                │
│  │  解释执行 (解释器)      │──→ 立即启动, 无编译等待                          │
│  │  - 模板解释器           │    - 每条字节码对应一段 native 模板              │
│  │  - 无优化              │    - 执行速度约 1/10 ~ 1/100 编译后代码           │
│  └──────┬───────────────┘                                                │
│         │ 计数器到达阈值                                                    │
│         ▼                                                                │
│  ┌──────────────────────┐                                                │
│  │  热点检测              │                                                │
│  │  - 方法调用计数器       │                                                │
│  │  - 回边计数器           │                                                │
│  │  - 计数器衰减           │                                                │
│  └──────┬───────────────┘                                                │
│         │ 热点识别完毕                                                     │
│         ▼                                                                │
│  ┌──────────────────────────────────────┐                                │
│  │  分层编译 (Tiered Compilation)        │                                │
│  │  ┌──────────────────────────────────┐│                                │
│  │  │ Level 0: 纯解释执行 (无编译)      ││                                │
│  │  │ Level 1: C1 无 profiling        ││                                │
│  │  │ Level 2: C1 基础 profiling      ││                                │
│  │  │ Level 3: C1 完整 profiling      ││                                │
│  │  │ Level 4: C2 完整优化             ││                                │
│  │  └──────────────────────────────────┘│                                │
│  └──────────────────────────────────────┘                                │
│         │                                                                │
│         ▼                                                                │
│  ┌──────────────────────┐          ┌──────────────────┐                  │
│  │  JIT 核心优化          │          │  去优化 (Deopt)   │                  │
│  │  - 方法内联 (最重要)    │──→ 假设  │  - 类加载导致     │                  │
│  │  - 逃逸分析            │  不成立  │  - 类型变化       │                  │
│  │  - 锁消除              │          │  - 回退到解释执行  │                  │
│  │  - 标量替换            │          │  - 重新编译       │                  │
│  │  - 循环优化            │          └──────────────────┘                  │
│  │  - 边界检查消除        │                                                │
│  └──────────────────────┘                                                │
└──────────────────────────────────────────────────────────────────────────┘

四、核心考点速记

1. 解释执行 vs 编译执行

维度解释执行 (Interpreter)编译执行 (JIT Compiler)
启动速度极快(无编译延迟)慢(需要预热)
峰值性能低(~1/10 编译代码)高(接近 native 代码)
内存消耗高(CodeCache 存储编译代码)
优化能力无优化C1 ~100 种优化,C2 ~1000 种优化
适用场景冷代码、罕见路径热点代码、频繁执行路径
关键参数-XX:CompileThreshold=10000

2. C1 与 C2 对比

维度C1 (Client)C2 (Server)
编译速度快(<50ms/方法)慢(>1s/方法)
优化强度中等(~100 种优化)激进(~1000 种优化)
逐方法耗时亚毫秒级秒级
代码质量中等极高
CodeCache 占用较少较多

3. 逃逸分析三件套

优化作用效果
栈上分配 (Stack Allocation)非逃逸对象 → 栈上分配零 GC 开销
标量替换 (Scalar Replacement)非逃逸对象 → 分解为标量字段对象完全消除
锁消除 (Lock Elimination)非逃逸对象 → 移除同步线程安全锁自动消除

4. 分层编译 5 级

层级名称编译方式profiling说明
0解释执行无编译纯解释,启动阶段
1C1 简单C1 编译简单 C1,不收集 profile
2C1 基础C1 编译调用/回边计数有限 profiling
3C1 完整C1 编译类型 + 分支 profile为 C2 做准备
4C2 极限C2 编译使用 L3 profile极限优化

五、面试高频追问一览

追问关联笔记频次
为什么需要解释器和编译器共存?**解释执行与编译执行**极高
JIT 如何判断哪些代码需要编译?**解释执行与编译执行**
什么是分层编译?为什么需要 5 级?**C1与C2编译器与分层编译**极高
C1 和 C2 有什么区别?**C1与C2编译器与分层编译**
什么是去优化 (Deoptimization)?**C1与C2编译器与分层编译**
方法内联为什么是最重要的 JIT 优化?**方法内联和逃逸分析**极高
逃逸分析如何工作?**方法内联和逃逸分析**极高
标量替换和栈上分配有什么区别?**锁消除与标量替换**
什么是锁消除?**锁消除与标量替换**
如何分析 JIT 编译日志?**JITWatch使用**

📚 相关链接

  • **字节码指令集概览** — 字节码是执行引擎的操作对象
  • **分配策略(栈上分配与TLAB与大对象)** — 逃逸分析的实战效果
  • **synchronized的JVM实现** — 锁消除的底层原理衔接
  • **JVM文库设计文档**

Knowledge4J — Java 知识库