How to Shrink Spring Boot Microservices to 30 MB with Spring Native
This article walks through the memory‑shortage problem of deploying multiple Spring Cloud Alibaba microservices on a single 2‑CPU 4‑GB server, explains JVM tuning, introduces Spring Native, and provides a step‑by‑step guide—including environment setup, GraalVM installation, Maven configuration, and Docker image building—to achieve millisecond‑level startup and dramatically reduced memory usage.
Introduction
When deploying a Spring Cloud Alibaba microservice project with seven services on a single Alibaba Cloud server (2 CPU, 4 GB), each Spring Boot fat‑jar consumes about 500 MB, and additional components such as Nacos, Redis, Sentinel, RocketMQ, and ELK consume over 2 GB, leaving insufficient memory for the services.
Initial JVM tuning was applied:
# JVM initial heap size (-Xms) defaults to 1/64 of physical memory
-Xms128m
# JVM maximum heap size (-Xmx) defaults to 1/4 of physical memory
-Xmx128m
# Thread stack size (-Xss) typically 256 k
-Xss256k
# Parallel GC threads (usually equal to CPU cores)
-XX:ParallelGCThreads=2When free heap drops below 40 %, the JVM expands the heap up to -Xmx; when free heap exceeds 70 %, it shrinks toward -Xms. Setting -Xms and -Xmx equal avoids heap resizing after each GC.
Even after tuning, memory usage remained around 100‑200 MB per service, far from the desired tens of megabytes.
Why Spring Native?
Spring Native leverages GraalVM native image compilation to produce lightweight native executables, improving Java’s competitiveness in cloud‑native environments. Officially, a Spring Native image containing Spring Boot, Spring MVC, Jackson, and Tomcat is about 50 MB.
Benefits observed:
Application startup in milliseconds.
Runtime memory consumption dramatically lower (≈50 MB).
Longer build time (a simple Hello World may take ~2 minutes).
Practical Guide
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
1. Install GraalVM
Download from https://www.graalvm.org/downloads/ and set JAVA_HOME to the GraalVM directory.
2. Install native‑image
gu install native-imageIf the command fails, manually download the installer JAR from GitHub , extract, and run gu install -L native-image* in the bin folder.
3. Configure Maven (pom.xml)
A minimal pom.xml for Spring Native:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
</parent>
<groupId>ltd.pcdd</groupId>
<artifactId>spring-native</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
<spring-native.version>0.11.1</spring-native.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.11.1</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
<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>
<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>
</env>
</image>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-release</id>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-release</id>
<url>https://repo.spring.io/release</url>
</pluginRepository>
</pluginRepositories>
</project>4. Build the native image
Run the following Maven commands (skip tests to speed up):
mvn clean
mvn -Dmaven.test.skip=true spring-boot:build-imageThe build process consumes high CPU and memory but finishes successfully, producing a Docker image named spring-native.
5. Run the container
List images, then create and start a container: docker run -p 8080:8080 spring-native Docker Desktop shows the application starts in about 59 ms and uses roughly 28 MB of RAM.
6. Comparison
Without Spring Native, the same Spring Boot application starts in ~3 seconds and consumes ~511 MB of RAM.
Conclusion
Using Spring Native with GraalVM and Spring Boot Buildpacks can dramatically reduce startup time to the millisecond level and cut memory usage to tens of megabytes, making it suitable for resource‑constrained environments. For production use, refer to the latest official Spring Native documentation.
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.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
