这两个概念是理解 Java 性能优化和 JVM 工作原理的核心。
1️⃣ 解释执行(Interpretation / Interpreter)
概念
解释执行是指 JVM 直接读取 .class 文件(字节码),然后逐条将字节码翻译成机器码执行。
- 字节码是一种中间语言(平台无关)
- 解释器(Interpreter)逐条执行字节码
- 不生成永久机器码,只是临时执行
优点
-
跨平台
- 字节码可以在任何有 JVM 的平台上运行
-
启动快
- 不需要做复杂的编译优化,直接执行
-
适合短时间运行的程序
- 小程序或脚本式执行
缺点
-
速度慢
- 每条字节码都要被翻译一次,频繁调用会累积开销
-
无法充分优化
- 无法针对具体 CPU 架构做深度优化
2️⃣ JIT(Just-In-Time 编译器)
概念
JIT 是 即时编译器 ,它的目标是 提高程序运行速度。
- JVM 在运行时监控哪些代码被频繁执行(热点代码)
- 将这些热点字节码 编译成机器码(native code)
- 机器码直接在 CPU 上执行,不再经过解释器
总结一句话:解释执行慢,JIT 可以让常用代码"飞起来"
3️⃣ JVM 执行流程(加入 JIT)
- 类加载 :JVM 加载
.class文件 - 字节码校验:保证安全
- 解释执行:初始执行字节码
- 热点探测:JVM 统计方法调用次数和循环次数
- JIT 编译:把热点方法编译成机器码
- 机器码直接执行:速度大幅提升
所以 Java 程序通常是 解释执行 + JIT 编译结合,既保证跨平台,又有接近本地代码的性能。
4️⃣ 为什么不直接全量 JIT?
-
编译开销大
- JVM 不可能在程序启动时把全部字节码都编译成本地机器码
-
空间浪费
- 有些方法可能只执行一次,全量编译反而占用内存
-
动态优化
- JIT 可以根据实际运行情况优化热点代码,做内联、循环展开、寄存器分配等高级优化
5️⃣ 对比:解释执行 vs JIT
| 特性 | 解释执行 | JIT |
|---|---|---|
| 执行方式 | 每条字节码即时翻译 | 热点字节码编译成本地机器码 |
| 性能 | 较慢 | 接近本地代码 |
| 启动时间 | 快 | 编译会增加启动时间 |
| 优化能力 | 基本没有 | 可以做复杂优化(内联、循环展开、寄存器分配) |
6️⃣ 举个形象比喻
- 解释执行 :像 翻译官,每次说一句话就翻译一次
- JIT :像 提前翻译成书面稿,之后直接朗读,速度快很多
在JVM执行流程中,第三步,解释执行,这里是在干嘛呢,将所有的字节码编译成机器码吗
不是的,这一步 解释执行(Interpretation) 并不是把所有字节码都编译成机器码,而是 边读边执行。我帮你仔细拆解一下。
1️⃣ 解释执行的核心
当 JVM 执行字节码时,解释器做的事情是:
-
读取一条字节码指令
- 比如
iload_1(加载局部变量1到操作数栈)
- 比如
-
查找对应的解释逻辑
- JVM 内部有一个映射表,每条字节码对应一个操作函数
-
执行操作
- 把操作数栈或局部变量栈修改,或者调用方法等
-
移动到下一条字节码
- 循环执行,直到方法执行完成
✅ 关键点:每条字节码在解释执行时都是临时翻译成机器码并执行一次,不会生成完整的机器码文件或永久存储的可执行代码。
2️⃣ 举例说明
假设有方法:
java
int sum(int a, int b) {
return a + b;
}
编译后的字节码大概是:
iload_1 // 将 a 压入操作数栈
iload_2 // 将 b 压入操作数栈
iadd // 栈顶两个值相加
ireturn // 返回结果
解释执行时的过程:
- JVM 读到
iload_1→ 临时生成 CPU 指令,把 a 放到栈上 → 执行 - JVM 读到
iload_2→ 临时生成 CPU 指令,把 b 放到栈上 → 执行 - JVM 读到
iadd→ 临时生成 CPU 指令,栈顶两个值相加 → 执行 - JVM 读到
ireturn→ 返回结果
注意:每条字节码都是 即时解释并执行一次,没有生成完整的机器码文件。
3️⃣ 为什么不把所有字节码一次性编译?
-
启动速度:
- 一次性编译所有字节码会很慢,程序启动会被拖慢。
-
内存浪费:
- 有些方法可能永远不执行,如果全量编译就浪费内存。
-
运行时优化:
- JIT 可以根据实际运行情况优化热点代码。
- 如果全量编译,JIT 就没机会做针对热点的高级优化。
✅ 总结
- 解释执行 = "边读边执行",每条字节码临时转换成 CPU 指令执行
- 不是一次性把所有字节码变成机器码
- JVM 会统计哪些代码频繁执行,然后交给 JIT 编译器生成机器码(提高性能)