You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何降低Docker中Spring Boot应用的内存占用?JVM参数调优未生效

Why Your Minimal Spring Boot App Uses 100MB Memory & How to Reduce It

Great question! Let's break down why your basic Spring Boot + Web app is consuming ~100MB of memory (even after setting -Xmx/-Xms), and walk through actionable steps to cut that usage significantly.

First: Why -Xmx/-Xms Didn't Help

The docker stats metric shows the entire container's RSS (Resident Set Size), which includes way more than just the JVM heap:

  • JVM heap (controlled by -Xmx/-Xms)
  • Metaspace (stores class metadata)
  • Code cache (compiled bytecode)
  • Thread stacks (each thread has its own stack)
  • Direct memory (used by libraries like Tomcat)
  • Overhead from the JVM process itself and the container's base OS

Your initial -Xmx50M only limits the heap, but all those other components were still using their default (often large) allocations. That's why you saw almost no change in total memory usage.

Actionable Optimization Steps

1. Tune JVM Parameters for Container Environments

Add these JVM flags to your JAVA_OPTS to control all memory areas, not just the heap:

JAVA_OPTS="-Xmx50M -Xms50M -XX:MaxMetaspaceSize=30M -XX:ReservedCodeCacheSize=20M -Xss512k -XX:+UseContainerSupport -Djava.awt.headless=true"

Let's break down what each does:

  • -XX:MaxMetaspaceSize=30M: Limits class metadata storage (Spring Boot doesn't need the default unlimited space)
  • -XX:ReservedCodeCacheSize=20M: Reduces the cache for compiled bytecode
  • -Xss512k: Cuts each thread's stack size from the default 1M (Tomcat uses fewer active threads than you might think, so this saves a lot)
  • -XX:+UseContainerSupport: Critical! Tells Java 8u191+ to respect Docker's memory limits (without this, JVM assumes it has access to the entire host's memory)
  • -Djava.awt.headless=true: Disables unused AWT components (irrelevant for web apps)

2. Switch to a Lighter Servlet Container

The default Tomcat server adds noticeable overhead. Swap it for Undertow or Jetty, which are more memory-efficient:
Update your pom.xml to exclude Tomcat and add Undertow:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

This alone can cut memory usage by 15-25MB.

3. Use a Minimal Docker Base Image

The openjdk:8-jre-alpine image is okay, but you can go lighter:

  • Eclipse Temurin Alpine: More optimized than the vanilla OpenJDK image: eclipse-temurin:8-jre-alpine
  • Distroless Images: Stripped-down images with only the JVM and necessary libraries (no shell, no extra OS tools): gcr.io/distroless/java:8

You can also use a multi-stage build to reduce the final image size (and indirectly lower runtime overhead):

# Build stage
FROM maven:3.8.6-openjdk-8 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

# Runtime stage
FROM eclipse-temurin:8-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/demo.jar .
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/demo.jar"]

4. Trim Unnecessary Dependencies & Auto-Configurations

Spring Boot's auto-config is convenient, but it loads components you might not need:

  • Remove spring-boot-starter-test from the runtime build if you're not running tests in production
  • Exclude auto-configurations you don't need. For example, if you don't use databases:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class DemoApplication {
    // ...
}

5. Upgrade to Spring Boot 3.x + GraalVM Native Image (For Maximum Savings)

If you can upgrade beyond Java 8, Spring Boot 3.x supports GraalVM native images. This compiles your app to a native machine code binary, eliminating most JVM runtime overhead. A native Spring Boot web app can run in as little as 20-30MB of memory!

Expected Results

After applying steps 1-3, you should see your container's memory usage drop to 60-70MB. Combine that with step 5, and you can get it down to under 30MB.

内容的提问来源于stack exchange,提问作者Вячеслав

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:48:27