【Java基础面试题003】Java的JIT | AOT是什么?
回答重点
Java中的JIT编译器(Just-In-Time,即时编译)是一种在程序运行时将字节码转为机器码的技术。
因为这种转换是在程序运行时即时进行的,因此得名"Just-In-Time"。
JIT监测到热点代码(频繁执行的代码段)时,就将这段Java代码提前编译成本地机器码,空间换时间,减少解释执行的开销,提高运行效率,也使得Java代码接近本地代码的性能。
(本地代码:指的是当前机器的经过编译后CPU可直接执行的机器码,性能会非常高)
Java的AOT(Ahead-Of-Time,预编译)是一种在编译期将所有或部分字节码转换成机器码。这是一个静态过程,发生在应用程序运行之前。
扩展知识
热点代码(Hotspot Code)
JIT编译器重点优化"热点代码",即被多次调用的方法,还有被多次执行的循环体。通过分析代码执行频率,JIT能识别这些热点并进行优化编译
JIT的优化编译采用了多种技术:如方法内联(Inlining)、逃逸分析(Escape Analysis)、循环展开(Loop Unrolling)等,使得编译后的机器码更加高效
JIT编译的类型
C1编译效率比C2快,但是优化效果不如C2
- C1(Client Compiler):用于快速启动的轻量级优化,适用于客户端应用程序
- C2(Server Compiler):用于长时间运行的重量级优化,适用于服务端的应用程序
JIT的调优
JVM提供了多种参数用于调优JIT编译器,如-XX:+PrintCompilation用于输出编译信息,-XX:TieredStopAtLevel控制JIT编译级别等
通过调优,可以在启动时间和运行性能之间取得平衡
JVM将执行状态分成了5个层次:
0层,解释执行(Interpreter)
1层,使用C1即时编译器编译执行(不带profiling)
2层,使用C1即时编译器编译执行(带基本的profiling)
3层,使用C1即时编译器编译执行(带完全的profiling)
4层,使用C2即时编译器编译执行
AOT的工作原理
AOT编译是在构建阶段的编译期间对全部Java字节码进行静态分析,并将其编译为目标平台的机器码。编译后的代码可以直接运行在目标硬件上,无需在运行时通过JVM进行解释或即时编译
(构建阶段包括:源代码编译,依赖管理,资源处理,AOT编译,打包和发布)
AOT的优点
- 快速启动:由于代码已经编译为本地机器码,AOT减少了程序启动时的编译开销,适合需要快速启动的应用场景
- 更小的内存占用:在不需要JIT编译器的情况下,AOT编译减少了JVM的内存占用
AOT的缺点
缺乏运行时优化:AOT编译器由于缺乏运行时信息,AOT 只能基于静态分析进行代码优化,无法像JIT编译器那样利用运行时的动态信息进行深度优化。可能导致在长时间运行的应用程序中性能低于JIT
平台依赖性:AOT编译出的机器码是针对特定平台的,缺乏跨平台的灵活性
AOT的使用场景
也就是可以不需要JIT编译器的情况
①部分资源有限的嵌入式系统,这些设备通常具有较小的内存和处理能力,AOP能提供一个轻量级的解决方案;
②还有简单脚本工具,桌面小工具;
③还有某些容器化环境,希望缩短启动时间,无需再容器运行时依赖JIT编译
以及对启动性能比较敏感的场景
Java自带的AOT工具
- GraalVM:GraalVM是一个多语言虚拟机,支持Java的AOT编译。它可以将Java应用程序编译成独立的本地可执行文件,这些文件不依赖JVM,即可直接运行在操作系统中
- jaotc:在Java9中引用的jaotc工具可以将Java字节码编译为AOT的本地代码,不过jaotc的 使用在生产环境中并不广泛