如何进一步降低Spring Boot应用内存占用?JVM参数配置合理性咨询
Hey Krish, let's dive into your question about optimizing memory usage for your 7 Spring Boot apps on a 4GB server. First, let's tackle whether your current JVM params are reasonable, then look at more ways to cut down memory footprint.
1. Are your current JVM parameters reasonable?
Your java -Xmx64m -Xss256k -jar test.jar setup does lower memory usage, but there are some critical risks to watch out for:
- -Xmx64m: This is an extremely tight heap limit for a Spring Boot app running Eureka Client, Data JPA, and RabbitMQ. Even with optimized code, sudden traffic spikes, JPA batch data loads, or RabbitMQ message backlogs could easily trigger
OutOfMemoryError: Java heap space. I'd recommend starting with at least-Xmx128mand then using Actuator's/actuator/metrics/jvm.memory.usedendpoint to monitor actual heap usage—adjust the limit based on how close you are to hitting it during peak loads. - -Xss256k: Reducing the thread stack size from the default (usually 1MB) saves memory, but be cautious. If your app has deep recursion, complex web request processing, or a large number of concurrent threads, this could lead to
StackOverflowError. For most Spring Boot apps,-Xss512kis a safer balance between memory savings and stack safety. Also, remember total stack memory equalsnumber of threads * Xss—if each app runs 50 threads, 7 apps would use ~8.75GB of stack memory with 256k limits, which is way over your 4GB server capacity. You'll need to cap thread counts (more on that later) if you stick with this value.
2. Further steps to reduce memory usage
Here are actionable, low-risk tweaks to trim memory even more:
A. Strip out development-only dependencies
You're including Devtools and Test components—these are not needed in production and add unnecessary memory overhead:
- For Maven, mark them as test/runtime-only in your
pom.xml:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> - For Gradle, use
testImplementationfor test dependencies and exclude Devtools entirely in production builds.
B. Disable unused Spring Boot auto-configurations
Cut down on unnecessary bean creation by turning off auto-configs you don't use:
- Add
excludeto your@SpringBootApplicationannotation:@SpringBootApplication(exclude = { DevToolsAutoConfiguration.class, // Exclude other unused configs, e.g., if you don't need specific Actuator endpoints HealthIndicatorAutoConfiguration.class }) - Restrict Actuator exposure in
application.properties:management.endpoints.web.exposure.include=health,info management.endpoint.health.show-details=never
C. Tune thread pool sizes
Each thread consumes stack memory, so reducing thread counts will directly cut total memory usage:
- Tomcat web threads:
server.tomcat.max-threads=20 server.tomcat.min-spare-threads=5 - RabbitMQ consumer threads:
spring.rabbitmq.listener.simple.concurrency=1 spring.rabbitmq.listener.simple.max-concurrency=5 - JPA connection pool (e.g., HikariCP):
spring.datasource.hikari.maximum-pool-size=5 spring.datasource.hikari.minimum-idle=2
D. Use a trimmed custom JRE with jlink
Default JREs include many unused modules (like JavaFX, CORBA). Use jlink to create a lightweight JRE with only the modules your app needs:
- List required modules with:
jdeps --list-deps your-app.jar - Build a custom JRE:
jlink --module-path $JAVA_HOME/jmods --add-modules java.base,java.sql,java.naming --output custom-jre - Run your app with this trimmed JRE:
custom-jre/bin/java -Xmx128m -Xss512k -jar test.jar
This can reduce JRE memory footprint by 30-50%.
E. Optimize GC and heap parameters
- Use the Serial GC instead of G1 (default for modern JVMs) — it has lower memory overhead for small heaps:
java -Xmx128m -Xss512k -XX:+UseSerialGC -jar test.jar - Limit direct memory (used by RabbitMQ, HikariCP, etc.):
java -Xmx128m -Xss512k -XX:MaxDirectMemorySize=32m -jar test.jar
F. Try Spring Native (advanced)
Compile your app to a native image with GraalVM. This eliminates reflection and dynamic proxy overhead, often reducing memory usage to <100MB per app. Note that not all dependencies (e.g., some JPA providers) support GraalVM, so you'll need to test compatibility first.
Final Notes
Start with dependency cleanup and thread tuning first—these are low-effort, high-impact changes. Then monitor your app's memory usage with Actuator to fine-tune JVM params. Avoid setting -Xmx too low; it's better to have a small buffer than deal with OOM errors in production.
内容的提问来源于stack exchange,提问作者Krish




