Java 云原生 Graal AOT 编译器的未来

发布于:2024-10-24 编辑:匿名 来源:网络

Java 语言固有的突出特性是“一次编译,随处运行”。这个特性得益于JVM平台的支持。

Java程序通常被编译为JAR或WAR包,并依赖JVM和Servlet容器来运行。其底层运行时JVM采用JIT(即时编译)模式来执行程序代码。

JVM 在运行时编译、优化和动态执行代码,这通常会导致更高的内存使用量。这样做的好处是可以利用JIT来热更新和热部署程序,并且JVM可以在运行时动态分析程序,实时优化程序,使其达到最佳性能。

云原生面临的问题随着云计算的发展,服务器程序的运行和部署方式发生了巨大的变化。尤其是在云原生(Cloud Native)场景下,服务器程序被打包到容器中运行。

在这种环境下,传统的容器化Java程序面临着打包后的镜像文件过大的问题。镜像文件需要包含JRE和各种第三方库,导致镜像体积较大,占用磁盘空间较多。

目前云计算的计费方式也发生了变化,采用按需分配的实时计费方式,根据程序的内存使用情况和运行时间进行计费。这与传统IDC自托管机房服务器程序的长期运行形成鲜明对比。

按需分配的计费方式显然更加划算,因此优化Java程序在容器环境中的运行方式就变得尤为重要。 Serverless 面临的问题 JVM 的传统工作原理需要程序员首先将编写好的 Java 程序打包成 JAR 或 WAR 包。

这是普通Java开发人员可以进入的程序编译和构建阶段。然而,当程序运行时,底层JVM会执行很多复杂的操作,包括内存管理、垃圾回收、即时编译等,需要先在JRE中启动JVM来加载程序所需的字节码。

Tomcat服务器,然后加载WAR包中的字节码文件来运行Servlet容器中的服务。这个过程非常耗时。

下图展示了整个传统Java程序从源代码到程序执行各个阶段的工作流程: 下图展示了传统Java运行时执行程序的生命周期。首先,应用程序开发人员将 *.java 源代码编译为字节码和 jar 依赖项。

通过maven build将包打包成单独的jar包。执行java -jar xxx.jar命令时,首先要启动JRE中的JVM程序,因为JVM本身也是一个独立的程序,对应$JAVA_HOME\bin目录下的java。

当JVM启动时,系统中会创建一个进程。 ,将需要运行的jar包和JRE标准库中的class文件加载到JVM内存中,找到main方法开始解释执行。

程序运行一段时间后,JVM充分获取Java程序的一些执行数据信息,开始对程序进行JIT,实时编译和优化程序。只有对程序进行了JIT优化,才能将程序直接编译成像C/C++一样的Native Code程序。

表现。在云计算推动的Serverless架构场景中,Java的JIT模式并不适合。

无服务器应用程序需要能够快速启动以响应事件驱动的请求,并在空闲时自动关闭和销毁以释放服务请求期间使用的内存。但这种需求与传统Java程序运行模型背道而驰,导致Java不适合Serverless场景。

这就是业界所说的“冷启动”问题。为了解决这个痛点,Oracle实验室推出了新的JDK产品GraalVM JDK。

与传统的JDK相比,该产品内置了Java静态编译工具和新的虚拟机。与传统 JVM 不同,GraalVM 支持多种语言。

虚拟机的混合编程也是其亮点之一。 GraalVM中的静态编译工具不仅支持将Java编译成二进制可执行文件,还支持JavaScript、Python等其他语言的编译优化功能。

本文仅关注 GraalVM 对 Java 程序的 AOT(Ahead-Of-Time)编译。解决方案。

使用GraalVM AOT编译Java程序的方案可以显着缩短启动时间并减少内存占用,使Java程序更适合在Serverless环境中运行。通过AOT编译,编译器生成Native Code二进制文件,对应平台架构机器码程序。

这种方式不需要像JIT那样依赖JVM操作,在内存和磁盘使用上都有显着的提升。下图展示了AOT编译流程。

在编译阶段,对程序进行静态分析。通过其内置工具来分析Java源代码中的依赖关系。

所有依赖关系和代码执行逻辑都被提前编译成机器代码。缺点也是显而易见的,也是可能的。

JIT模式下的动态反射功能将会丢失。如上所示,在AOT模式下,运行时进程被置于程序构建阶段。

构建阶段将对Java程序进行静态代码分析和依赖可达性分析,并编译其与生产平台对应的所有依赖软件包。可执行二进制文件。

AOT编译和优化 程序的AOT编译特别适合云应用程序。 AOT编译优化后的程序启动速度足够快,从而缩短启动时间,更直接地横向扩展云服务。

内存使用量比 JVM 模式要少得多。这对于在云中运行的容器启动的微服务尤其有利。

AOT的前提是完全封闭的运行空间,因为它消除了各种代码注入的可能性。例如,2016年震惊互联网的Log4j漏洞就是由于使用了Java中的动态类加载机制而发生的。

AOT编译后,程序不会出现类似的bug。下面的蜘蛛图详细展示了不同程序运行方式的差异: Java程序部署平台和主流容器技术之间,都是基于Linux系统,因此采用Ubuntu发行版作为基本的AOT编译和运行打包环境。

要 AOT 编译 Java 程序,必须首先安装 GraalVM JDK 发行版。可以从其官方网站 graalvm.org 下载并安装。

安装步骤与传统的基于 OpenJDK 的发行版相同。要在Linux中使用GraalVM提供的AOT静态编译功能,首先需要在操作系统中安装一些C/C++编译工具链。

在 Ubuntu 等基于 Debian 的系统中,执行以下命令: 代码语言:bash copy sudo apt -get install build-essential libz-dev zlib1g-dev 其中 build-essential 是 C 语言的开发包,包括很多工具,例如gcc制作gdb和libc函数库。这些工具和库对于编译 C 和 C++ 程序非常有用。

是必不可少的。libz-dev 和 zlib1g-dev 是用于压缩和解压缩的开发库。

这两个软件包提供了开发zlib库的头文件和开发工具,允许您在编写C/C++程序时链接和使用zlib压缩库。 GraalVM的AOT编译依赖这些工具来构建本地镜像。

默认情况下,GraalVM 的 AOT 编译在链接时通常会使用系统的标准 glibc 库,但在小型嵌入式设备或内存需求极低的环境中,glibc 并没有针对这些场景进行专门优化。相比之下,目前还有另一个专有的 musl 标准库实现。

musl 的开发重点是在内存受限的设备上表现良好。使用 musl 生成的二进制文件通常比使用 glibc 生成的二进制文件小。

因此,建议直接使用musl而不是glibc进行编译和链接优化。 GraalVM的AOT编译工具中提供了自定义选项,允许开发者自定义使用musl来优化生成的二进制文件。

有些Linux发行系统可能没有内置musl库,需要提前安装。如果需要源码安装,可以到musl.libc.org官网下载源码包,编译安装。

但这种方法需要手动配置和编译步骤,比较麻烦。建议使用以下方法。

通过别人已经编译好的x64位x86_64-linux-musl-native程序,将压缩包下载到指定位置即可使用。基于musl进行编译的前提是依赖musl工具链,但是GraalVM JDK中并没有提供相关的工具链支持。

需要提前下载x86_64-linux-musl-native和zlib文件,并创建一个用于存放musl工具。链的目录,解压到该目录下,集成x86_64-linux-musl-gcc和zlib进行编译安装。

步骤如下: 代码语言:bash copy # 创建工具存放目录 mkdir /usr/local/graal-aot-tools# 进入该目录 cd /usr/local/graal-aot-tools# 下载 x86_64-linux- musl 工具链 wget 并解压下载的 musl 工具链包 tar -zxvf x86_64-linux-musl-native.tgz# 将文件复制到工作根目录 cp -r x86_64-linux-musl-native/* .# 下载 zlib 依赖在 wget 解压 zlib 上依赖源码包 tar -zxvf zlib.tar.gz 通过特定的 TOOLCHAIN_DIR 环境变量指定 musl 工具链安装路径,graalvm 的 aot 编译器会通过这个变量来查找 x86_64-linux-musl 的位置: 代码language: bash copy export TOOLCHAIN_DIR="/usr/local/graal-aot-tools" export PATH="$TOOLCHAIN_DIR/bin:$ PATH"export CC="$TOOLCHAIN_DIR/bin/gcc"最后集成zlib和TOOLCHAIN_DIR进行编译然后安装,进入zlib源码安装目录,执行:代码语言:bash copy./configure --prefix=$TOOLCHAIN_DIR --static make make install配置完成后,就可以使用x86_64-linux-musl-gcc了命令检查musl工具链是否安装成功。如果您使用maven构建自动化项目,可以使用pom文件配置AOT相关构建参数来自动构建二进制文件: 代码语言:xml copy org .graalvm.buildtools native-maven-plugin ${native.maven.plugin.version} true build-native build package false ${bin.file.name} ${app.main.class} --gc=G1 --static <buildArg>--libc=musl --no-fallback 科技部落

© 2024 kejibuluo. All rights reserved.

隐私政策 | 免责声明 | 关于我们

本网站使用Cookies以确保您在我们网站上的最佳体验。继续使用本网站即表示您同意我们的隐私政策。

如果您有任何问题或需要联系我们,请发送电子邮件至 a445999612@gmail.com