Java应用生命周期-JVM视角

JIT启动预热

0.前言 0.1.Java程序执行过程 0.2.编译的快与慢 0.2.1.Java虚拟机(解释的(Interpreted)相对慢) 0.2.2.即时编译器(Just In Time Compiler)(相对快) 0.2.3.Java编译器(Java Compiler)(相对快) Eg: Graal编译器(既可以作为AOT编译器,又可以在JIT编译器中替换C2)、AOT(jaotc) 1.JIT编译过程 Java应用启动后,在完成类加载、字节码验证后,并不会马上触发JIT编译器进行编译,而是先由即时解释器进行解释和分析; 即时解释器在完成了初步的解释和分析后,JIT编译器会利用已经收集到的分析信息来查找热点(经常执行的代码部分),有了热点代码后,C1就可以对这些热点代码进行分析,基于分析的结果编译生成相对高效的目标机器代码,从而使得此时的Java虚拟机具有本机的代码性能,于此同时C1也会进行进一步的分析; C1在完成了进一步的分析后,C2就会利用C1产生的分析信息,进行更积极、更耗时的优化,此时C2会重新编译代码,以生成更高效的目标机器代码,从而更明显的提升Java虚拟机的代码性能。 综上所述,基于热点的更多信息,C1 性能提升更快,而 C2 性能提升更好。 2.当前需求 Azul可以在模拟环境下预热(模拟出热点方法和循环体),然后将结果注入生产环境,直接使用 C2 编译,减少运行时的编译时间。这对于证券行业报盘等场景很有效,因为这些场景一开始就需要高速运转。 横轴:JVM虚拟机达到最佳代码性能的时间; 纵轴:JVM最佳代码性能程度或比率; 毛刺:去优化和垃圾回收导致的。 3.问题 Azul可以在模拟环境中学习和训练,然后将训练结果集作为参考输入到生产环境中,以达到启动时的峰值效果。 并消除 GC毛刺。 3.1.当前问题 启动时间长; 需要很长时间Java虚拟机才可以达到Java虚拟机的最佳代码性能。 3.2.期望结果 启动时间短; 启动后Java虚拟机可快速达到最佳代码性能。 3.3.期望目标 在保证关键功能正确使用的前提下,显著降低再次启动耗时; 消除毛刺,使得Java虚拟机快速达到最佳代码性能。 4.问题分析 4.1.现在加速启动的方案有哪些? 4.1.1.CDS(Class Data Sharing,类数据共享) 功能定位: 将内部类、应用类、动态(自定义类加载器加载的类和省去dump classlist步骤)等表示转储到文件中(类加载器、jsa文件); 在每个 JVM 启动时共享 (CDS)。 不足: 没有优化或热点检测; 仅减少类加载时间; 启动速度加快不明显。 4.1.2.AOT(Ahead Of Time Compilation,提前编译,源码到机器码) 优点: 从一开始就“全速”,GraalVM 原生镜像可以做到这一点; 根据定义,AOT 是静态的,代码在运行之前进行编译,运行时编译代码没有开销; 内存占用小 不足: 不解释字节码; 没有热点分析; 没有代码的运行时编译,所以没有运行时字节码生成; 方法内联的有限使用; 反射是可能的,但很复杂; 无法使用推测性优化 (假设条件成立,如数组边界) 必须针对共同特征(如同名同参数等)进行编译 由于优化不彻底,所以总体性能通常会较低; 部署环境!=开发环境。...

January 23, 2024 · 2 min · 南小焘