Reducing Spring Boot Microservice Memory Usage with Spring Native on a Single 2C/4G Server
This tutorial explains how to address memory constraints when deploying multiple Spring Boot microservices on a single 2‑CPU, 4‑GB server by applying JVM tuning, installing GraalVM, configuring Spring Native 0.11.1 with Maven plugins, building native images, and deploying them via Docker, achieving startup times in milliseconds and memory consumption around 28 MB.
In the preface the author describes a personal project built with Spring Cloud Alibaba that consists of seven microservices, a Nacos service registry, Redis, Sentinel, RocketMQ, and ELK, all of which together consume more than 2 GB of RAM on a single Alibaba Cloud server (2 Cores, 4 GB RAM). Each Spring Boot service, packaged as a fat‑jar, uses roughly 500 MB without any JVM tuning.
To reduce memory usage the author first adds JVM options such as -Xms128m , -Xmx128m , -Xss256k , and -XX:ParallelGCThreads=2 , which lowers the per‑service footprint to 100‑200 MB but still falls short of the desired “tens of megabytes” goal.
Research leads to the adoption of Spring Native , a beta project that compiles Spring applications into native executables using GraalVM, promising millisecond‑level startup and significantly lower runtime memory (officially around 50 MB for a full Spring Boot stack).
Spring Native Overview
Spring Native enables the compilation of Spring Boot, Spring MVC, Jackson, Tomcat, and other dependencies into a native binary via the GraalVM native‑image compiler. The author includes a quoted description from the Spring Native README and a brief commentary on the trend of “native” runtimes in cloud‑native environments.
Practical Steps
1. Install GraalVM (graalvm‑ce‑java11‑21.3.0)
# download from https://www.graalvm.org/downloads/2. Set environment variables (JAVA_HOME, GRAALVM_HOME, PATH)
Only JAVA_HOME is strictly required for the Docker‑based method, but configuring all three is recommended.
3. Install the native‑image component
gu install native-imageIf the command fails, the author suggests manually downloading the native-image JAR from the GraalVM GitHub releases and extracting it.
4. Install Docker Desktop for Windows (link to official Docker documentation).
5. Configure pom.xml
The full Maven project file is provided, showing the parent Spring Boot 2.6.2, the spring-native dependency version 0.11.1, and the spring-aot-maven-plugin execution that generates AOT code.
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
</parent>
<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>
</env>
</image>
</configuration>
</plugin>
</plugins>
</build>
</project>Additional JVM arguments can be added under the <image><env> section, for example:
<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>6. Build the native image
mvn clean '-Dmaven.test.skip=true' spring-boot:build-imageThe build process is CPU‑intensive, often pushing CPU usage to 100 % and memory to 90 %+, but completes successfully, producing a Docker image named spring-native .
7. Run the container
docker run -p 8080:8080 spring-nativeDocker Desktop shows the container starting in about 59 ms, confirming the millisecond‑level startup claim. Memory consumption observed in Docker Desktop is roughly 28 MB, compared to >500 MB when running the same application without Spring Native.
The author notes that the article is for reference only and recommends consulting the latest Spring Native documentation for production use.
References: - Spring Native README on GitHub - Official Spring Boot Maven plugin documentation - GraalVM download page - Docker Desktop installation guide
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.