Cloud Native 17 min read

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.

Alibaba Cloud Native
Alibaba Cloud Native
Alibaba Cloud Native
Boost Java Startup Speed and Reduce Memory with GraalVM Static Compilation & ARMS

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.zip

Similar 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.sh

Dependency 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 --Carms

Static 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.

GraalVM application metric collection
GraalVM application metric collection
GraalVM application call chain
GraalVM application call chain
Startup speed and memory usage comparison
Startup speed and memory usage comparison
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

graalvmnative-imageJava Agentstatic compilation
Alibaba Cloud Native
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.