Boost Java Startup Speed and Reduce Memory with GraalVM Static Compilation & ARMS
This guide explains the challenges of Java cold‑start and high runtime memory in cloud‑native environments, introduces GraalVM static compilation and a novel static Java Agent instrumentation solution, and provides step‑by‑step instructions—including dependency installation, Maven configuration, pre‑run collection, and native image building—to enable observable, high‑performance Java applications.
Background
In the era of cloud‑native computing, enterprises demand rapid elasticity for their applications. Java, being an interpreted language with just‑in‑time (JIT) compilation, suffers from long cold‑start times and high runtime memory consumption, which hampers fast scaling.
Cold‑Start Issue
When a Java program starts, the JVM is loaded into memory, followed by class loading, interpretation, garbage collection, and finally JIT compilation. This multi‑stage process (VM init → App init → App active) leads to a noticeable cold‑start latency compared with statically compiled languages.
High Runtime Memory Issue
Even when idle, a Java process holds the JVM, JIT compiler, and garbage collector, all of which consume memory. Additionally, unnecessary classes are loaded and compiled, further increasing the memory footprint.
Static Compilation Technology
To address these problems, the GraalVM community (led by Oracle) introduced static compilation, which transforms Java applications into native executables that start at peak performance and use less memory. Alibaba, as a global advisory member of the GraalVM community, has refined this technology for e‑commerce and cloud scenarios.
Challenges with GraalVM Native Image
Dynamic features such as class loading, reflection, and dynamic proxies are disabled by default and require extra configuration.
Platform‑independence is lost.
Java Agents that rely on bytecode rewriting no longer work because bytecode does not exist at runtime.
Consequently, preserving the observability capabilities provided by Java Agents becomes a key problem.
Proposed Solution
Alibaba Cloud’s observability team, together with the language and compiler teams, designed a static Java Agent instrumentation approach. The solution consists of two phases:
Pre‑Running Phase : Mount both the OpenTelemetry (OTel) Java Agent and a custom Native Image agent. The OTel Agent transforms target classes (C → C') during a pre‑execution run, while the Native Image agent records the transformed classes.
Static Compilation Phase : Compile the original application together with the OTel Agent, the transformed classes, and configuration files. During compilation, class C is replaced by C', producing a native executable that already contains the instrumentation.
Java Agent Overview
A Java Agent works by registering a transformer that intercepts class loading. In the preMain stage, the agent can modify bytecode (e.g., class C becomes C'). The transformed class is then loaded by the JVM, enabling runtime enhancements.
Static Java Agent Instrumentation Solution
Because GraalVM native images lack a running JVM, the instrumentation must be applied before compilation. The custom Native Image agent intercepts class bytecode before and after transformation, records any changes, and stores them for the static compilation step.
Native Image Agent Enhancements
Additional logic was added to handle classes generated at runtime and to provide a premain configuration for the OTel Agent, ensuring GraalVM knows the entry point. Special APIs were implemented to collect and replace JDK classes without altering the JDK itself, and class shading was performed to emulate multiple class loaders.
ARMS Observability for GraalVM Applications
Using the above technique, the ARMS Java Agent can be bundled into the native image, allowing full observability (metrics, traces, logs) without sacrificing the benefits of static compilation.
Installation Steps
First, install the ARMS native probe appropriate for your region. Example for Hangzhou (East China 1):
wget "http://arms-apm-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zipSimilar wget commands exist for other regions (Shanghai, Beijing, Zhangjiakou, Shenzhen) with both public and VPC URLs.
After downloading, unzip and run the installation script:
sh install.shDependency Configuration
Add the following Maven dependency and profile to enable native image building:
<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>Replace /xxx/dynamic-configs with the path to your application's dynamic configuration files.
Pre‑Execution
Run the ARMS agent in a pre‑execution mode to collect all necessary configuration and transformed classes. Example script (modify parameters accordingly):
######## Please adjust parameters
export ARMS_LICENSEKEY=
export ARMS_APPNAME=
export PS=
export PORT=
export NATIVE_IMAGE_FILE=target/graalvm-demo
export JAVA_CMD="-javaagent:./arms-native/aliyun-java-agent-native.jar -jar target/graalvm-demo-1.0.0.jar"
########Execute:
sh ArmsAgentNative/run.sh --collect --jvm --CarmsStatic Compilation
Build the native image with Maven:
Run the compiled native binary with the ARMS agent attached:
Result Demonstration
After compilation, the native executable contains the ARMS agent code. Running the application yields observable metrics in the ARMS console.
Performance Impact
Tests on a 32 vCPU / 64 GiB / 5 Mbps environment show that GraalVM‑compiled Java applications achieve significantly lower startup latency and reduced memory usage while retaining full observability.
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 Native
We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.
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.
