理论派 | Theory

Java on Truffle:实现真正的元循环

作者 Oleg Šelajev 译者 张卫滨

GraalVM 21.0引入了一个新的JVM实现Java on Truffle,这是一个使用Java编写的Java虚拟机,从而提供了一种在GraalVM上运行Java代码的新方式。

本文最初发表于Graal VM的Medium博客站点,经原作者Oleg Šelajev授权由In-fo Q中文站翻译分享。

到目前为止,GraalVM已经提供了两种运行Java程序的方式:组合使用Java HotSpot VM和GraalVM JIT(just-in-time)编译器,以及使用GraalVM Native Image编译成原生可执行文件。

如今,我们很高兴地宣布一种在GraalVM运行Java的新方法。GraalVM 21.0引入了一个新的可安装的组件,叫做espresso,它提供了一个使用Java编写的JVM实现。

Java on Truffle在Java架构中的位置

Espresso使得通过Truffle框架运行Java代码成为可能,从而将Java提升到与GraalVM所支持的其他语言相同的级别。

尝试运行

尝试Java on Truffle是非常简单直接的。它可以使用gu命令,作为一个组件安装到基础GraalVM发行版中。

gu install espresso
gu install -Lespresso-installable.jar # if downloaded manually

安装之后,要在Java on Truffle运行你最喜欢的应用,只需要为java命令传递-truffle参数即可。

java -truffle -jar my App.jar

请下载Java on Truffle并尝试一下。这里有一些带有指令的示例应用,阐述了Java on Truffle的特殊功能。

注意,当前Java on Truffle的性能并不代表它在不远的将来的能力。目前它的峰值性能要比常规JIT模式下运行相同的代码慢好几倍。另外,预热也还没有进行优化。在这个初始发布版本中,我们完全专注于功能、兼容性,并让Java on Truffle开源,使其能够在更广大的社区中得到应用。

预计在我们即将发布的每个21.x版本中,性能(包括预热性能和峰值性能)将会得到迅速提升

现在,我们更加详细地看一下Java on Truffle是什么并探索一些它提供帮助的典型用例,尝试将该项目放到更大的GraalVM和Java生态系统中。

Java on Truffle

Java on Truffle是一个JVM实现,它使用了Truffle语言实现框架。它提供了Java虚拟机所有的核心组件:

• 字节码解释器

• 字节码校验器

• 单程(Single-pass)的class文件解析器

• 简单的对象模型

•使用Java语言编写的Java原生接口(Java Native Interface, JNI)实现

•使用Java实现的Java虚拟机

• Java Debug Wire Protocol(JDWP)

这个JVM实现有很重要的一点就是它是使用Java编写的。Java on Truffle是基于Java的Java(Java on Java)。自托管是Java虚拟机研究和开发领域的圣杯。

它所能做的就是运行Java程序。当然,它也可以运行用其他JVM语言编写的程序。从上面的列表我们可以看出,它还支持调试协议,所以我们也可以使用它调试Java应用。

Java on Truffle能够用于基于Java 8和Java 11的GraalVM发行版,所以从技术上来讲,你可以使用它来替代自己所选择的JVM。Java on Truffle目前是实验性的,速度还不是很快,所以现在不建议将其用于生产环境的工作负载,但是我们可以探索一下使用Java on Truffle运行应用程序都能实现哪些特性。

基于Java的Java

正如我们在前文所描述的,Java on Truffle是使用Java实现的。它是一个虚拟机实现,所以为了实际运行Java代码,它需要访问类库以及JDK提供的本地库和方法。Java on Truffle重用了GraalVM分发版的JAR和本地库。

因为它是使用Java实现的并且能够运行Java,这使得Java on Truffle具有了非常有意思的特性:它可以运行自己!事实上,Java on Truffle是一个元循环(metacircular)的虚拟机,它可以嵌套运行自己好几层(不过每次都会越来越慢)。

作为一个Java程序,它有很多优势。其中之一就是能够使用原生镜像编译成原生的可执行文件,在后面的章节中我们将会讨论一个很有意思的用例。

另外一个优势就是,对于Java开发人员来说,代码非常友好和熟悉,易于理解。读者可以考虑去Git Hub仓库查看它的源码。你的日常工具适用于它,你的IDE支持它,你可以像探索其他Java依赖那样去探索它的代码。这种透明度和熟悉度能够让Java on Truffle更加高效地应对变化。

将Java 11嵌入到Java 8中

Java on Truffle实际就是一个JVM,但它也是一个Java程序,这意味着你可以在其他Java程序中运行它。这就为将应用程序中的不同组件进行分割开辟了一个很有趣的途径。举例来说,如果你将Java on Truffle指向一个JDK 11,那么它就能运行Java 11。如果访问Java 8,那么它就会成为Java 8。如果你同时拥有这两个发行版的话,那么你就可以在Java 8的环境中运行Java on Truffle,并使用它来运行Java 11字节码,反之亦然。如果有个库只能用于Java 8,那么你可以迁移至更新的基础JDK,并且通过一些编程方面的努力让这个特定的库依然能够运行,这需要建立一种互操作性,在相同的Java进程中建立兼容的JDK 8环境。

混合AOT和JIT

因为Java on Truffle、Truffle、GraalVM编译器和运行Java on Truffle的所有其他必要的组件都是使用Java编写的,所以我们能够构建一个包含运行Java on Truffle基础设施的原生镜像可执行文件。

这意味着,我们可以基于Java应用,将一个JVM构建到它的里面,然后要么在JVM上运行该应用,要么以原生镜像的方式运行该应用。需要注意,在后面的情况中,Java on Truffle实际上可以执行任意的Java代码,这些代码不一定需要在构建的时候就得知道。

没错,Java on Truffle可以将JIT编译器和动态Java运行时用到一个提前编译的二进制文件中。

Java on Truffle允许为使用原生镜像构建的应用添加动态语言的特性

我们准备了一个样例应用来阐述这个理念。这是一个JShell实现的样例,它接受一个常规的JShell应用,该应用包含两个组成部分:前端的CLI应用和后端的计算引擎,我们将后者替换成了Java on Truffle实现。

实际上,它非常整洁地重用了原来实现中的所有类,只需加载它们即可。因此,示例应用程序的原始部分是连接托管Java部分和Java on Truffle部分的“胶水”代码。

这个示例可以被编译成原生可执行文件,以得到一个二进制文件,由于原生可执行文件的性能特征,它的启动速度比一般的JShell要快,而且仍然可以执行我们扔给它的Java代码。

下面是Java on Truffle实现的JShell加载并启动俄罗斯方块游戏的截图。

混合AOT和JIT对于那些不能利用原生镜像性能改进的应用程序来说是一个非常棒的可选方案,因为这些应用的功能依赖于动态代码,而动态代码不容易与原生镜像一起工作。

高级的类重定义

Java on Truffle有另外一项很酷的特性,比HotSpot更强大,这就是增强的热替换(Hot Swap)能力:在调试会话中,运行时改变类。

GraalVM 21.0支持如下的变化:

1.添加和移除方法

2.添加和移除构造器

3.从接口中添加和移除方法

4.改变方法的访问修饰符

5.改变构造器的访问修饰符

6. Lambda的变化

7.添加新的匿名内部类

8.移除匿名内部类

未来将会使热替换更强大的是支持对类字段的变化。该特性正在进行中,会在未来的释放版本中添加进来。

在IntelliJ IDEA调试器中重新加载修改的类

这个搭建过程与HotSpot相同:启动调试器、修改代码、重新编译类、在IDE调试器中点击“Reload the classes”并使用新代码恢复程序运行,下一次变更的代码就会生效。

GraalVM生态系统的支持

对于GraalVM语言从Truffle框架中获取的开发人员工具支持来说,Java on Truffle会使它们从中收益。

例如,你可以在运行应用的时候,使用某些java -truffle --cpusampler,这样的话就能让采样剖析器(profiler)在代码上运行。我们还可以启用跟踪剖析器或内存跟踪器,从而告诉我们代码的哪个部分产生了更大的内存压力。

生态系统的另一个方面是支持的语言。Java on Truffle允许我们创建多语言程序,不同的组件用不同的语言编写。关于如何加载用其他语言编写的代码、在不同语言之间导出和导入对象等细节,超出了本文的范围,但细节可以从文档中找到

下一步的计划

GraalVM 21.0是Java on Truffle的初始版本。现在它是一个实验性的组件,在接下来的版本中我们计划对它进行重大改善。

它有很多需要改进的地方,从支持javaagents,到与其他语言的互操作协议方面提供更好的实现,重大的性能改进等等。

我们将致力于这些和其他方面的改进,并且会非常乐意听到任何反馈、特性请求、潜在的用例、发现的问题和当前版本的不足之处。你可以通过SlackGit HubTwitter分享你的反馈。要想开始学习它,请前往graalvm.org/java-on-truffle

Java on Truffle是一种全新的、非常令人兴奋的运行Java代码的方式。请了解并考虑一下它所带来的可能性。