Java 9 引入了 aot 编译方式,能够将 class 文件直接编译成可执行二进制文件。目前 Java 9 的 early access 版本已经提供了编译工具,让我们来看看它的功能吧。

注意:按照 JEP 295 描述,目前版本的 AOT,仅支持 64 位 Linux 操作系统。

jaotc 使用

首先需要下载最新的Java 9(JDK),本文编写时,最新版本是Build 152。下载好的JDK 只需要解压即可使用,特别注意使用前设置好 PATH和JAVA_HOME两个环境变量,避免和机器上已经安装的 JDK 混淆。笔者安装到了 $HOME/bin/jdk-9,并设置了:

export PATH=~/bin/jdk-9/bin:$PATH

export JAVA_HOME=~/bin/jdk-9

需要使用jaotc,首先需要有个测试类,首先从 Hello World 开始:

class HelloWorld {

public static void main(String[] args) {

System.out.println("Hello World!");

}

}

代码非常简单,但是在执行 jaotc 之前,还需要将其编译成 class 文件,直接使用 javac 即可:

$ javac HelloWorld.java

执行成功之后,会生成 HelloWorld.class 文件。此时直接使用 java 命令,已经可以正常运行这个类:

$ java HelloWorld

Hello World!

这时,就可以基于这个 class 文件,通过jaotc命令将其编译成二进制文件了。

$ jaotc --output libHelloWorld.so HelloWorld.class

如果一切正常,会生成 libHelloWorld.so 文件。

如果出现类似Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/babydragon/bin/jdk-9/lib/libjelfshim.so: libelf.so.1: 无法打开共享对象文件: 没有那个文件或目录的错误,是因为jaotc需要依赖 libelf 动态链接库来创建 elf 文件(最终生成的 libHelloWorld.so 文件是一个静态链接的 elf 文件)。笔者使用的是 Gentoo 系统,需要安装 dev-libs/elfutils 包,以提供 libelf.so 这个动态连接库。安装之后可以通过ldd命令进行确认:

$ ldd $JAVA_HOME/lib/libjelfshim.so

linux-vdso.so.1 (0x00007ffd001f3000)

libelf.so.1 => /usr/lib64/libelf.so.1 (0x00007f25ea2ce000)

libc.so.6 => /lib64/libc.so.6 (0x00007f25e9f35000)

libz.so.1 => /lib64/libz.so.1 (0x00007f25e9d1d000)

/lib64/ld-linux-x86-64.so.2 (0x0000562318d51000)

前面通过jaotc命令成功生成了 libHelloWorld.so。虽然命令里面参照 JEP 295 的示例将生成的文件后缀设置成了 so,但如果使用ldd命令查看,会发现它其实是一个静态链接库:

$ ldd libHelloWorld.so

statically linked

通过nm命令,可以看见代码段中的函数入口:

$ nm libHelloWorld.so

0000000000002420 t HelloWorld.()V

0000000000002520 t HelloWorld.main([Ljava/lang/String;)V

最后,需要执行时需要通过参数-XX:AOTLibrary参数指定需要加载的经过 aot 预编译好的共享库文件:

java -XX:AOTLibrary=./libHelloWorld.so HelloWorld

注意:虽然已经将整个 HelloWorld 类都通过 jaotc 编译成共享库文件,运行时仍然需要依赖原有的 HelloWorld.class 文件。

此时执行的输出,和之前不使用 AOT 的输出完全相同。

来把大的——将 java.base 模块编译成 AOT 库

JEP 295 中已经说明,在 Java 9 初始发布的时候,只保证 java.base 模块可以被编译成 AOT 库。

继续参照 JEP 295,创建 java.base-list.txt 文件,内容主要是排除一些编译有问题的方法,具体内容参照原文。

然后执行命令:

jaotc -J-XX:+UseCompressedOops -J-XX:+UseG1GC -J-Xmx4g --compile-for-tiered --info --compile-commands java.base-list.txt --output libjava.base-coop.so --module java.base

在笔者的机器上(i7-6600U + 16G 内存 + 256G NVMe SSD),排除上述方法之后,编译时间大约为 9 分多钟。

48878 methods compiled, 4 methods failed (497771 ms)

Parsing compiled code (1126 ms)

Processing metadata (15811 ms)

Preparing stubs binary (0 ms)

Preparing compiled binary (104 ms)

Creating binary: libjava.base-coop.o (5611 ms)

Creating shared library: libjava.base-coop.so (7306 ms)

Total time: 542536 ms

完成之后,就可以使用 AOT 版本的 java.base 模块:

java -XX:AOTLibrary=java_base/libjava.base-coop.so,./libHelloWorld.so HelloWorld

同样,针对 AOT,jvm 也新增了参数打印哪些方法是通过加载 AOT 预编译库执行。

java -XX:+PrintAOT -XX:AOTLibrary=java_base/libjava.base-coop.so,./libHelloWorld.so HelloWorld

输出可以和不使用 java.base 的 AOT 进行比较,发现不使用 java.base 的 AOT 库,只能会加载 libHelloWorld.so 中对应的方法。

$ java -XX:+PrintAOT -XX:AOTLibrary=./libHelloWorld.so HelloWorld

11 1 loaded ./libHelloWorld.so aot library

105 1 aot[ 1] HelloWorld.()V

105 2 aot[ 1] HelloWorld.main([Ljava/lang/String;)V

Hello World!

$ java -XX:+PrintAOT -XX:AOTLibrary=java_base/libjava.base-coop.so,./libHelloWorld.so HelloWorld

13 1 loaded java_base/libjava.base-coop.so aot library

13 2 loaded ./libHelloWorld.so aot library

[Found [Z in java_base/libjava.base-coop.so]

[Found [C in java_base/libjava.base-coop.so]

[Found [F in java_base/libjava.base-coop.so]

[Found [D in java_base/libjava.base-coop.so]

[Found [B in java_base/libjava.base-coop.so]

[Found [S in java_base/libjava.base-coop.so]

[Found [I in java_base/libjava.base-coop.so]

[Found [J in java_base/libjava.base-coop.so]

31 1 aot[ 1] java.lang.Object.()V

31 2 aot[ 1] java.lang.Object.finalize()V

...

输出太长,节选部分输出,我们可以看见 java 基础类及其方法都通过 AOT 的方式进行加载。

实用吗?

目前 AOT 的局限有:

仅支持 64 位 Linux 操作系统:这个问题不是很大,毕竟大部分线上服务器都能够满足;

操作系统需要预装 libelf 库,以确保能够生成 elf 文件:这个问题也不大,仅生成时需要;

AOT 编译和执行环境需要相同:毕竟是二进制文件,引入了平台相关性;

Java 9 最初发布时,只支持 java.base 模块可以编译成 AOT 库;

目前只支持 G1 和 Parallel GC 两种 GC 方式:前面没有提到,AOT 编译时的 JVM 参数和运行时需要相同,也包括 GC 方式,也就是说如果用了 AOT,JVM 实际运行时也只能使用这两种 GC 方式之一;

可能会无法编译通过动态生成 class 文件或者修改字节码的 java 代码(如 lambda 表达式、反射调用等):这个可能会比较坑,后面会讲到;

JVM 运行时参数设置必须和 AOT 库编译时相同;

AOT 可能带来的好处,是 JVM 加载这些已经预编译成二进制库之后,可以直接调用,而无需再将其运行时编译成二进制码。理论上,AOT 的方式,可以减少 JIT 带来的预热时间,减少 Java 应用长期给人带来的“第一次运行慢”感觉。

不过,本文使用的 HelloWorld 过于简单,无法通过对比得出 AOT 是否可以减少 JVM 初始化时间。笔者尝试对一个小型 springboot 应用进行 AOT 化,但是 springboot 框架本身无法在 Java 9 中运行。同时直接对 spring-core 的 jar 包执行 jaotc 也因为各种依赖问题而失败。

经过各种尝试,目前 Java 9 的 AOT 功能还处于很初步的阶段:

缺少 maven 等管理工具集成,无法方便的对项目指定 jar 或者 class 文件比构建 AOT 库;

大型框架还没有官方支持,构建 AOT 库难度比较高;

大型框架如果直接提供 AOT 库,可能会因为由特定平台构建,而在本地无法使用;

期待 Java 9 正式发布的时候,能够对 AOT 有更好的支持。

found linux系统wget出现not_Java 9 AOT 试用:仅支持 64 位 Linux和java.base 模块编译相关推荐

  1. java 位运算取8位_Java 9 AOT 试用:仅支持 64 位 Linux和java.base 模块编译

    Java 9 引入了 aot 编译方式,能够将 class 文件直接编译成可执行二进制文件.目前 Java 9 的 early access 版本已经提供了编译工具,让我们来看看它的功能吧. 注意:按 ...

  2. 计算机是否支持64位操作系统,教你查看自己的电脑是否支持64位win7系统的方法...

    问:我想要安装windows7的64位系统,但是听说有的电脑并不能装64位系统,不知道自己的电脑是否支持64位win7系统,能不能告诉我要如何查看自己的电脑是否支持64位win7系统呢? 答:如果电脑 ...

  3. linux 汇编 push rbp,无法从汇编(yasm)代码调用64位Linux上的C标准库函数

    我有一个用汇编编写的函数foo,并在 Linux(Ubuntu)64位上用yasm和GCC编译.它只是使用puts()向stdout输出一条消息,它的外观如下: bits 64 extern puts ...

  4. 1037u支持64位linux吗,英特尔® 赛扬® 处理器 1037U

    发行日期 首次推出产品的日期. 光刻 光刻是指用于生产集成电路的半导体技术,采用纳米 (nm) 为计算单位,可表示半导体上设计的功能的大小. 内核数 内核数是一个硬件术语,它表示单个计算组件(裸芯片或 ...

  5. 1037u支持64位linux吗,树莓派B+ BCM2835 vs Celeron 1037U性能对比测试

    树莓派B+ BCM2835 700MHz单核 512M内存 Celeron 1037U 1.8G Hyper-V虚拟 单核 1GB内存 安装测试软件: sudo apt-get install sys ...

  6. c4d支持mac系统渲染器有哪些_在macOS Catalina发布前检查哪些应用程序不支持64位系统...

    macOS Catalina 让你喜欢的种种 Mac 体验都更进一步.你可以领略音乐.播客这两款全新 Mac app 的表演:在 Mac 上畅享各款自己心爱的 iPad app:拿起 iPad 和 A ...

  7. 解决内联汇编64位Linux系统调用提示Bad Address

    在参考<Linux 下系统调用的三种方法>这篇文章的时候,前面的syscall()和chmod()两种方法完成系统调用chmod都可以正常执行. 但当我使用内联汇编时,程序执行提示errn ...

  8. centos 64位linux系统下安装appt(只有32位)命令的apktool工具包的笔记

    centos 64位linux系统下安装appt命令的apktool工具包的笔记,有需要的朋友可以参考下. 首先,安装apktool包 1. wget http://android-apktool.g ...

  9. Linux系统驱动全吗,linux系统需要给硬件安装驱动程序么?谁推荐一下linux系统阿~要驱动最全...

    需要,不过大部分linux都自带,少量的也都有自动安装文件 比如ati的显卡驱动什么的. 之前还自己写过驱动,linux的驱动比windows的驱动透明度高很多 大部分硬件基本上 都可以识别的 也可以 ...

最新文章

  1. 信息系统项目管理师:第4章:项目整体管理与变更管理-章节真题
  2. 实验室装水的容器叫什么_@实验员丨实验室超纯水机正确取水,你做到了吗?...
  3. 磁盘寻道算法 Python实现
  4. ​【文末有福利】股票跨度——真实世界的算法
  5. security java的配置_springSecurity之java配置篇
  6. ISO 639-1語言列表
  7. srvany把程序作为Windows服务运行
  8. 用云原生的思维践行云原生,一切皆服务
  9. 43岁,转行当了大学老师
  10. 使用mysql语句进行多表联查(以三个表为例)
  11. extjs中dateField日期精确到时分秒的扩展控件
  12. sql server数据库练习
  13. 人工智能AI 01人工智能入门指南
  14. python取出数组大于某值_计算矩阵中大于某个值的所有值
  15. 小波分析用于阈值去噪
  16. noi题目P4206 [NOI2005] 聪聪与可可
  17. 费诺编码的MATLAB递归实现
  18. ZZ关于椭圆标准方程转参数方程
  19. 微软SDL流程终极整理总结
  20. dmesg 时间戳转换为时间

热门文章

  1. SpringMVC——处理方法返回值的可选类型
  2. 50、BGP配置实验之社团属性community
  3. 《计算复杂性:现代方法》——第0章 记 号 约 定 0.1 对象的字符串表示
  4. C#_LINQ(LINQ to Entities)
  5. 微软低代码工具 Power Apps 配置不当,暴露3800万条数据记录
  6. 黑客利用 Gatekeeper 0day 攻击 MacOS 计算机
  7. 微软发布 Autodesk FBX 漏洞带外安全公告,将于5月推出补丁
  8. MFC添加View的方法
  9. Python面试必须要了解的15个问题
  10. IOS --xcode删除Provisioning Profiles文件