JIT 编译:运行时只编热代码
是什么。 JIT 是 Just-In-Time,即时编译,运行时把热点字节码编译成机器码。对面是解释执行(逐条翻译,启动快、执行慢)和 AOT,Ahead-Of-Time,提前编译(启动前全编好,执行快,但看不到运行时信息)。
为什么有。 大部分时间花在小部分热点上,解释执行跑热点慢。但全量提前编译也不对,很多代码只跑一次,编它们是纯开销,而且提前编看不到运行时才知道的事:实际类型、分支走向。所以:先解释执行,跑着记着,只编变热的代码。
分层编译(HotSpot)。 0 层解释执行;1 到 3 层是 C1,Client Compiler,编译快、优化少;4 层是 C2,Server Compiler,编译慢、优化多,或者 Graal 通过 JVMCI 顶替这个位置。计数器(方法调用加循环回边)触发升级,假设破了就去优化退回去。
机制,只点名。 Profiling 记类型、分支、调用目标。推测性优化先假设、埋检查、假设破了去优化。内联去掉虚调用开销,让后续优化能跟上。OSR,On-Stack Replacement,循环中途把栈帧换成编译码。逃逸分析加标量替换让不逃逸对象不上堆,Graal 的部分逃逸分析比 C2 激进。
代价。 预热(启动慢、跑热才快)、编译耗 CPU、CodeCache 占地方、假设反复破会去优化风暴。长期跑的服务划算,短命的命令行程序一般不划算。