实现细节
与其他使用 Truffle 实现的语言一样,Espresso 可以作为原生可执行文件或在 HotSpot 上运行(目前仅在 Linux 上支持)。在第一种情况下,当 Espresso 运行时被编译成原生可执行文件时,它不需要 HotSpot 来运行 Java。但是,它需要一个标准的 Java 核心库(Java 8 的 rt.jar 库或 Java 11+ 的 lib/modules 文件,以及相关的原生库:libjava
、libnio
等等)。
Espresso 是一个最小化的 Java VM,它实现了 VM 的所有核心组件,包括:
- 字节码解释器
- 字节码验证器
- 单个 Java 类文件解析器
- 简单的对象模型
- Java 本地接口 (JNI) 的 Java 实现
- Java 中的虚拟机实现
- Java 调试线协议 (JDWP)
Espresso 重新使用 GraalVM 中的所有 JAR 文件和原生库。所有原生库和方法都通过 Truffle 本地函数接口 (JNI) 加载/访问/调用。JNI 句柄在 Espresso 中实现,例如,所有 Truffle NFI 方法只接收和返回基本类型。为了性能,一些方法被替换,例如,Math.sqrt
、System.arraycopy
,避免了昂贵的原生转换。
一些原生库可能包含静态数据,如果从多个 Espresso 上下文甚至从 Espresso 和 HotSpot 上运行的 Java 中使用,这些静态数据会发生冲突。在 Linux 上,Espresso 使用 Truffle NFI 的功能来尝试在隔离的命名空间 (dlmopen
) 中加载库。这只有在使用 glibc
的 Linux 上才能使用,并且有很多限制。在运行原生可执行文件时,此模式不会被使用,因为不会与 HotSpot 发生冲突。
当前限制 #
- Espresso 未实现 JVM 工具接口 (JVMTI)。因此,它不支持
-agentlib
或-agentpath
VM 选项。 - Espresso 未实现
java.lang.instrument
接口。因此,它不支持-javaagent
VM 选项。 - Espresso 目前使用 Java 核心库中的标准原生库。这需要允许多语言
Context
进行原生访问。由于这些库的加载方式(通过 Truffle 本地函数接口 (JNI)),因此在 HotSpot 上运行只在 Linux(使用glibc
)上有效。作为原生可执行文件的一部分运行在 Linux、Windows 和 macOS 上有效,但目前仅限于一个上下文。 - 对 Java 管理扩展 (JMX) 的支持是部分的,一些方法可能返回部分数据。
- 调试器协议实现 (JDWP) 与 HotSpot 相比,缺少一些功能。它将正确报告支持的 功能。特别是需要枚举所有 Java 对象的操作不受支持。但是,它确实支持 HotSpot 不支持的几个热重载情况。
- 当
java.MultiThreaded
选项设置为“false”时,引用处理 将不会发生。根据应用程序的不同,这可能会导致资源泄漏。请注意,如果 Espresso 在启用单线程语言的上下文中运行(例如,JavaScript),则此选项会自动设置为“false”。 - Espresso 还不支持 多语言 API。但是,它提供了访客 Java 多语言 API,如
polyglot.jar
中所述。有关详细信息,请参阅 与 Truffle 语言的互操作性。