Cloud Native 14 min read

How to Shrink Spring Boot Microservices to 30 MB with Spring Native

This article walks through diagnosing memory pressure in a multi‑service Spring Cloud Alibaba project, applying JVM tuning, installing GraalVM and Spring Native, configuring Maven and Docker Buildpacks, and finally building and running a native Spring Boot image that starts in milliseconds and consumes only a few dozen megabytes of RAM.

Java Backend Technology
Java Backend Technology
Java Backend Technology
How to Shrink Spring Boot Microservices to 30 MB with Spring Native

Introduction

When deploying a seven‑service Spring Cloud Alibaba micro‑service system on a single 2‑CPU, 4 GB Alibaba Cloud server, the author ran out of memory because each Spring Boot fat‑jar consumed about 500 MB and supporting services (Nacos, Redis, Sentinel, RocketMQ, ELK, MySQL) added another 2 GB.

JVM Parameter Optimization

# JVM initial heap size (default 1/64 of physical memory)
-Xms128m
# JVM maximum heap size (default 1/4 of physical memory)
-Xmx128m
# Thread stack size (256 k is usually enough)
-Xss256k
# Parallel GC threads (usually match CPU cores)
-XX:ParallelGCThreads=2

The author set -Xms and -Xmx to the same value to avoid heap resizing after each GC, and left ParallelGCThreads at the default because the server has only two CPUs.

What Is Spring Native?

Spring Native compiles Spring applications into native executables using GraalVM, dramatically reducing startup time and memory footprint, which is especially valuable for cloud‑native deployments.

Spring Native provides beta support for compiling Spring applications into native executables with the GraalVM native‑image compiler, enabling lightweight container deployment.
Java’s traditional reliance on the JVM makes it bulky for cloud‑native scenarios; GraalVM‑based native images aim to make Java applications as lightweight as Go or Rust.

Practical Steps

Environment

OS: Windows 10 21H1

IDE: IntelliJ IDEA 2021.2.3

JDK: graalvm‑ce‑java11‑21.3.0

Maven: 3.6.3

Docker Desktop for Windows: 20.10.12

Spring Boot: 2.6.2

Spring Native: 0.11.1

Install GraalVM

Download from https://www.graalvm.org/downloads/ and extract.

Configure Environment Variables

Set JAVA_HOME to the GraalVM directory and add %JAVA_HOME%\bin to PATH. The author recommends configuring all three variables ( JAVA_HOME, GRAALVM_HOME, PATH) for reliability.

Install native‑image

Run gu install native-image. If it fails, download the installer JAR from GitHub and install manually.

gu install native-image

Build the Native Image

Two approaches are possible:

Use Spring Boot Buildpacks (via spring-boot-maven-plugin) to produce a Docker image that already contains the native executable.

Use the GraalVM native‑image Maven plugin to generate a standalone .exe without Docker.

Because the services are deployed with Docker, the author chose method 1.

Method 1 – Spring Boot Buildpacks

Add the following plugin configuration to pom.xml (excerpt shown):

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <image>
      <builder>paketobuildpacks/builder:tiny</builder>
      <env>
        <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
      </env>
    </image>
  </configuration>
</plugin>

Run the build command:

mvn clean '-Dmaven.test.skip=true' spring-boot:build-image

The build consumes a lot of CPU and memory but finishes successfully, producing a Docker image named spring-native.

Run the Container

List images, then create and start a container from the spring-native image.

The application starts in about 59 ms and uses roughly 28 MB of RAM, as shown in Docker Desktop logs.

For comparison, the same service without Spring Native takes around 3 seconds to start and consumes over 500 MB of memory.

Further Configuration

Additional JVM options can be added under the <image><env> section, for example:

<image>
  <builder>paketobuildpacks/builder:tiny</builder>
  <env>
    <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
    <BPE_APPEND_JAVA_TOOL_OPTIONS>-Xms128m</BPE_APPEND_JAVA_TOOL_OPTIONS>
    <BPE_APPEND_JAVA_TOOL_OPTIONS>-Xmx128m</BPE_APPEND_JAVA_TOOL_OPTIONS>
    <BPE_APPEND_JAVA_TOOL_OPTIONS>-Xss256k</BPE_APPEND_JAVA_TOOL_OPTIONS>
    <BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:ParallelGCThreads=2</BPE_APPEND_JAVA_TOOL_OPTIONS>
    <BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:+PrintGCDetails</BPE_APPEND_JAVA_TOOL_OPTIONS>
  </env>
</image>

Refer to the official Spring Boot Maven plugin documentation for more options: https://docs.spring.io/spring-boot/docs/2.6.2/maven-plugin/reference/htmlsingle/#build-image .

Conclusion

Using Spring Native together with GraalVM and Spring Boot Buildpacks can reduce startup time to the millisecond level and shrink memory usage to under 30 MB, making Java micro‑services much more suitable for cloud‑native environments.

For the latest details, consult the Spring Native reference guide: https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/index.html
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.

DockerSpring Bootjvm-tuninggraalvmSpring Native
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

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.