How GraalVM Static Compilation Boosts Cloud‑Native Java Performance and Observability
This article explains the challenges of Java cold start and high memory usage in cloud‑native environments, introduces GraalVM static compilation and a novel static Java Agent solution, and provides step‑by‑step instructions for installing ARMS, configuring dependencies, and achieving fast, observable native images.
GraalVM Static Compilation
With the rapid rise of cloud‑native technologies, providing extreme elasticity for enterprise applications is a core demand for digital upgrades. Java, as an interpreted language with runtime JIT compilation, suffers from slow cold start and high runtime memory consumption compared to statically compiled languages.
Cold‑Start Problem
When a Java program starts, the JVM is loaded into memory (VM init), then application classes are loaded (Class Load), interpreted, and finally JIT‑compiled. This multi‑stage process leads to significant cold‑start latency.
High Runtime Memory Usage
Even idle Java processes allocate memory for the JVM, JIT compilation, and garbage collection. Additionally, unnecessary bytecode may be loaded and compiled, increasing memory overhead.
Static Compilation Technology
To address these issues, the GraalVM community introduced static compilation, which ahead‑of‑time compiles Java programs into native executables, eliminating cold‑start delays and reducing memory usage. Alibaba, a global advisor to the GraalVM community, has further refined this technology for e‑commerce and cloud scenarios.
Limitations of Traditional Java Agent
When compiled to a GraalVM native image, dynamic features such as class loading, reflection, and Java agents no longer function because bytecode is absent. This also removes the platform‑independent nature of Java and disables existing observability capabilities provided by Java agents.
Solution Overview
Alibaba Cloud’s observability team, together with the language and compiler teams, designed a static Java Agent injection method. The solution consists of two phases:
Pre‑Running Phase: The application runs with both the OpenTelemetry (OTel) Java Agent and a Native Image agent. The OTel agent transforms target classes (e.g., C → C') while the Native Image agent records the transformed classes.
Static Compilation Phase: The original application, OTel agent, transformed classes, and configuration are compiled together. During compilation, original classes are replaced with their transformed versions, producing a native executable that includes the observability logic.
The Native Image agent is extended with an interceptor that records class bytecode changes, ensuring all necessary classes are captured for static compilation.
ARMS Integration Steps
To enable ARMS observability for GraalVM applications, follow these steps:
Install the ARMS native probe for your region (e.g., Hangzhou, Shanghai, Beijing, Zhangjiakou, Shenzhen) using wget "<region‑url>" -O ArmsAgentNative.zip and unzip.
Run sh install.sh to install the probe.
Download a GraalVM JDK version that supports observability.
Install Maven (if not already present) and set JAVA_HOME and MAVEN_HOME environment variables.
Add the following Maven dependency to your project:
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>arms-javaagent-native</artifactId>
<version>4.1.11</version>
<type>pom</type>
</dependency>
</dependencies>
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<fallback>false</fallback>
<buildArgs>
<arg>-H:ConfigurationFileDirectories=native-configs,/xxx/dynamic-configs</arg>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>Update the path /xxx/dynamic-configs to point to your application's dynamic configuration files. Pre‑execution: Mount the ARMS agent and run the application in pre‑run mode to trigger all code paths, ensuring the agent captures necessary classes. Use the provided script ArmsAgentNative/run.sh --collect --jvm --Carms after setting environment variables such as ARMS_LICENSEKEY , ARMS_APPNAME , PORT , etc. Static Compilation: Execute mvn -Pnative package to build the native image, then run sh ArmsAgentNative/run.sh --native --Carms to start the compiled binary.
Performance Results
Tests on a 32 vCPU/64 GiB environment show that GraalVM‑compiled Java applications retain full observability while achieving significantly lower startup latency and runtime memory consumption.
Metric and trace data collected by ARMS demonstrate the effectiveness of the solution.
Additional Notes
For special cases, such as handling JDK classes during GraalVM compilation, custom APIs and shading techniques are employed to ensure the native image includes necessary transformations without modifying the JDK itself.
Readers interested in deeper details or further assistance can join the DingTalk group (ID: 80805000690) for additional resources and discussion.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Observability
Driving continuous progress in observability technology!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
