GraalVM 24 正式发布阿里巴巴贡献重要特性 —— 支持 Java Agent 插桩

作者:林子熠、饶子昊

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 平台上线了该功能。目前在 GraalVM 24 中发布的是支持 Java agent 的第一步,其余能力将在 GraalVM 的后续版本中陆续发布。

实现原理

Java agent 是一种动态修改 Java 运行时代码的技术,无需应用程序修改任何内容,由 Java agent 在运行时修改实际要执行的内容,广泛使用于 Java 应用监控领域。Java 应用在上线后一般都会接入以 Java agent 为核心的可观测平台,监测运行时行为。

Java agent 的实现有两点基础,GraalVM 都不具备:

  1. JVM 的 premain 机制。如果希望应用在运行时自始至终用到的都是经过变换的类,那么就需要在应用正式开始前就把修改类的需求告诉 JVM,然后在首次加载类时进行修改。Java 规范要求 agent 必须要提供名为 premain 的函数,在里面实现注册变换、选项解析、上下文环境初始化等工作。JVM 则提供了相应的执行入口,保证在执行主函数之前会调用各个 agent 的 premain 函数。但是在 GraalVM 的运行时中并没有设计过该机制,所以 agent 就不会有被调用的机会。

  2. 对 Java 的字节码进行变换。修改字节码,改变目标的运行时行为。在 JDK24 之前基于 ASM 接口修改,在 JDK24 之后基于 Class-File 接口。GraalVM 将 Java 应用编译为 native 应用后不再保留字节码,因此失去了可以修改的目标,而且 native 应用本身也不支持动态修改。

GraalVM 因为不能支持 Java agent 而失去了可观测能力,这一功能缺失阻碍了很多用户适配 GraalVM。

我们在 GraalVM 上实现对 Java agent 的支持就是解决了以上两个问题:

首先,在 GraalVM 的编译时识别用户的 premain 函数,将它们加入编译队列,然后注册到运行时的 premain 入口。这样编译制品 native image 就会在运行时成功找到 premain 函数,然后执行其中的业务逻辑。这次在 GraalVM 24 中发布的就是这部分功能。

其次,将 Java agent 的类转换动作从运行时提前到编译时。因为基于 premain 的 agent 即使在 JVM 中,也是在首次加载目标类的时候对其进行变换,然后将变换好的结果返回给类加载器的。使用者首次见到的类就是变换后的,那么对于使用者来说,编译时变换和运行时变换就是等价的。所以我们只要将 agent 转换好的类编译进 native image 就可以了。那么问题就转换为如何在编译时获得 agent 变换后的类。

关于这个问题,我们的实现思路是先让挂载 agent 的 Java 应用执行一次,在此过程中把经过 agent 转换的类转储到磁盘,然后在编译时使用这些类。

通过ARMS对GraaIVM应用进行观测

目前,阿里云应用实时监控服务平台 ARMS(复制至浏览器打开或文末阅读原文直达:www.aliyun.com/product/arm... ARMS 对 GraalVM 应用进行可观测的方法请参考 ARMS 官方文档(链接见文末)。

当完成静态编译后,相关可执行 Native Image 文件中就包含了 ARMS 可观测 Java Agent 的代码。执行按照正常 GraalVM 应用部署运行方式进行运行即可,以下是其在 ARMS 控制台上的部分可观测数据采集效果:

GraalVM 应用指标数据采集效果

GraalVM 应用调用链数据采集效果

如下图是一个通过 Spring Schedule 发起定时任务调用 Restful 接口,然后通过 HttpClient 对外进行调用的示例:

性能效果

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

总结

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

相关链接(复制链接至浏览器打开):

1.GraalVM 24 特性列表链接:

www.graalvm.org/release-not...

2.JDK 24 特性列表链接:

jdk.java.net/24/release-...

3.Class-File API:

openjdk.org/jeps/484

4.GraalVM 应用接入 ARMS 链接:

help.aliyun.com/zh/arms/app...

5.使用 ARMS 对 GraalVM 应用进行可观测方法:

help.aliyun.com/zh/arms/app...

相关推荐
阿里云云原生13 小时前
LLM 不断提升智能下限,MCP 不断提升创意上限
云原生
云上艺旅16 小时前
K8S学习之基础七十四:部署在线书店bookinfo
学习·云原生·容器·kubernetes
云上艺旅1 天前
K8S学习之基础六十八:Rancher创建deployments资源
学习·云原生·容器·kubernetes·rancher
rider1891 天前
【4】搭建k8s集群系列(二进制部署)之安装master节点服务(kube-apiserver)
云原生·容器·kubernetes
GreenMountainEcho1 天前
Kubernetes 入门篇之 Node 安装与部署
云原生·容器·kubernetes
alden_ygq1 天前
k8s statefulset pod重启顺序
云原生·容器·kubernetes
云上艺旅2 天前
K8S学习之基础七十二:Ingress基于Https代理pod
学习·云原生·容器·https·kubernetes
liux35282 天前
k8s之Ingress讲解
云原生·容器·kubernetes
阿里云云原生2 天前
函数计算支持热门 MCP Server 一键部署
云原生