
2025年3月18日Oracle双箭齐发,正式发布了JDK 24和GraalVM 24,带来了众多新特性。
JDK 24在性能和安全性方面均有改进(特性列表),其中较大的一处改动是在JDK中用新的Class-File API取代了ASM接口,使Java agent在动态修改Java字节码时更加方便快捷。与之相呼应,GraalVM 24在提升运行时性能、降低native image制品大小、提升调试体验等各方面的改进和提升之外(特性列表),也迈出了在native image中静态化支持Java agent插桩的第一步。这就是在发布中提到的Premain Support for Java Agents新特性,即支持Java agent的premain机制。
这是由阿里巴巴贡献到GraalVM社区的新特性。阿里巴巴是GraalVM全球顾问委员会的唯一中国代表,阿里云程序语言与编译器团队和可观测团队合作实现了GraalVM应用的无侵入可观测能力,并在ARMS平台上线了该功能。目前在GraalVM24中发布的是支持Java agent的第一步,其余能力将在GraalVM的后续版本中陆续发布。
实现原理
Java agent是一种动态修改Java运行时代码的技术,无需应用程序修改任何内容,由Java agent在运行时修改实际要执行的内容,广泛使用于Java应用监控领域。Java应用在上线后一般都会接入以Java agent为核心的可观测平台,监测运行时行为。
Java agent的实现有两点基础,GraalVM都不具备:
- JVM的premain机制。如果希望应用在运行时自始至终用到的都是经过变换的类,那么就需要在应用正式开始前就把修改类的需求告诉JVM,然后在首次加载类时进行修改。Java规范要求Java agent必须要提供名为premain的函数,在里面实现注册变换、选项解析、上下文环境初始化等工作。JVM则提供了相应的执行入口,保证在执行主函数之前会调用各个agent的premain函数。但是在GraalVM的运行时中并没有设计过该机制,所以agent就不会有被调用的机会。
- 对Java的字节码进行变换。修改字节码,改变目标的运行时行为。在JDK24之前基于ASM接口修改,在JDK24之后基于Class-File接口。GraalVM将Java应用编译为native应用后不再保留字节码,因此失去了可以修改的目标,而且native应用本身也不支持动态修改。
GraalVM因为不能支持Java agent而失去了可观测能力,这一功能缺失阻碍了很多用户适配GraalVM。
我们在GraalVM上实现对Java agent的支持就是解决了以上两个问题。
首先,在GraalVM的编译时识别用户的premain函数,将它们加入编译队列,然后注册到运行时的premain入口。这样编译制品native image就会在运行时成功找到premain函数,然后执行其中的业务逻辑。这次在GraalVM24中发布的就是这部分功能。
其次,将Java agent的类转换动作从运行时提前到编译时。因为基于premain的agent即使在JVM中,也是在首次加载目标类的时候对其进行变换,然后将变换好的结果返回给类加载器的。使用者首次见到的类就是变换后的,那么对于使用者来说,编译时变换和运行时变换就是等价的。所以我们只要将agent转换好的类编译进native image就可以了。那么问题就转换为如何在编译时获得agent变换后的类。
关于这个问题,我们的实现思路是先让挂载agent的Java应用执行一次,在此过程中把经过agent转换的类转储到磁盘,然后在编译时使用这些类。
通过 ARMS 对 GraalVM 应用进行观测
目前阿里云应用实时监控服务平台(ARMS https://www.aliyun.com/product/arms) 已经基于上述方案,完成了对Java Agent的GraalVM静态编译能力支持。具体使用ARMS对GraalVM应用进行可观测的方法请参考ARMS官方文档:https://help.aliyun.com/zh/arms/application-monitoring/use-cases/connect-graalvm-applications-to-arms
当完成静态编译后,相关可执行 Native Image 文件中就包含了 ARMS 可观测 Java Agent 的代码。执行按照正常 GraalVM 应用部署运行方式进行运行即可,以下是其在 ARMS 控制台上的部分可观测数据采集效果:
GraalVM应用指标数据采集效果

GraalVM应用调用链数据采集效果
如下图是一个通过 Spring Schedule 发起定时任务调用 Restful 接口,然后通过 HttpClient 对外进行调用的示例:

性能效果
我们基于上述方案,也对 GraalVM 应用在启动速度和运行时内存占用进行了一些测试验证,发现 Java 应用基于 GraalVM 静态编译后,不仅可以正常使用开箱即用的可观测能力,运行时内存占用和启动延时仍然有巨大的优化效果(以下测试在32 vCPU/64 GiB/5 Mbps环境中完成)。

总结
GraaLVM24正式发布了由阿里巴巴贡献的premain机制,拉开了对Java agent的静态编译支持大幕。
尽管GraalVM社区对无侵入式可观测的支持还处于早期阶段,但阿里云ARMS平台已经上线了完整的静态编译可观测能力支持。欢迎对上述相关产品能力和技术方案感兴趣的读者试用ARMS,希望获取相关资料和做进一步交流探讨的读者请加钉钉群: 80805000690。
