Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

即时编译(进阶)

复习

  • 字节码与虚拟机:解释执行字节码
  • 编译器:把代码编译成机器码
  • 循环优化:优化优先盯热点

本章为进阶内容,零基础读者可以跳过,不影响后续阅读。

TL;DR

  • 即时编译(JIT)在程序运行时把热点代码编译成本地机器码
  • 它结合了解释的灵活与编译的速度
  • 只编译热点,避免整体编译的开销
  • 代价是运行时编译的复杂与启动时的“预热”

正文

  纯解释执行太慢,而完全静态编译又不够灵活。即时编译(JIT,Just-In-Time compilation)想两头都占:程序运行起来之后,一边跑,一边把最值得编译的部分编译成机器码。

运行中“抓热点”

  JIT 的做法,和我们前面讲循环优化时的思路一脉相承——盯着热点

  1. 程序先以解释(或字节码)的方式跑起来
  2. 运行时监控:哪些方法、哪些循环被反复执行(热点)
  3. 把热点代码编译成本地机器码
  4. 之后这些热点就改走机器码,快得多

  冷门代码就继续解释执行,不必为它们花编译时间。把编译的力气,花在真正经常跑的地方。

还能“看情况”优化

  JIT 有一个静态编译比不了的优势:它知道程序运行时到底发生了什么。

  比如,它可以观察到“这个变量实际上一直是整数类型”,于是按整数来优化这段代码,生成更快的机器码。这种“根据运行时的实际情况做优化”,是纯静态编译做不到的——静态编译器只能靠猜测。运行时信息,让优化更有底气。

代价:预

  但 JIT 不是没有代价:

  • 运行时编译要花时间,程序刚启动时可能偏慢(常叫“预热”)
  • 虚拟机和 JIT 本身很复杂,占用额外的内存与资源
  • 优化得越激进,编译开销和不确定性也越大

  于是,很多系统采用混合模式:先解释、或者快速编译一版,等热点出现再深度优化。先跑起来,再越跑越快。 这也是现代很多语言运行时的常见策略。

思考题 1

  即时编译相比纯解释,快在哪里?

思考题 2

  即时编译为什么只编译“热点”代码?

小结

知识点

  • JIT 在运行时把热点代码编译成本地机器码
  • 它结合解释的灵活与编译的速度
  • 可利用运行时信息做更贴合实际的优化
  • 代价是编译开销、复杂度与启动预热

参考资料

  1. Wikipedia(zh):即时编译:运行时把代码编译为机器码
  2. Wikipedia(zh):虚拟机:JIT 通常运行于其中的环境

思考题答案(仅供参考)

思考题 1

  因为纯解释每次执行都要逐条分析指令,而 JIT 会把反复执行的热点代码一次性编译成高效的本地机器码,之后直接执行机器码,省去了反复解释的开销,因此快得多。

思考题 2

  因为编译要花时间和资源。若把所有代码都编译,既拖慢启动、又可能为很少执行的代码浪费力气。只编译热点,能把编译成本集中到真正影响性能的那部分代码上,收益最高、代价最小。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪