如何降低内嵌Tomcat的Spring Boot应用内存占用?相关疑问解答
Spring Boot Memory Optimization & Deployment Questions Answered
Hey there, let's walk through each of your questions with practical, actionable advice based on your scenario of running 7 Spring Boot JARs on a single server:
1. Are there more memory optimization approaches available?
Absolutely—here are some targeted tweaks beyond just adjusting JAVA_OPTS:
- Trim down dependencies:
- Remove
devtoolsandtestdependencies from production builds entirely (they're only for development). Use Maven/Gradle profiles to exclude them in prod. - Replace
spring-boot-starter-webwithspring-boot-starter-webfluxif your services can use non-blocking I/O—this eliminates the heavy embedded Tomcat footprint and uses Netty instead. - Exclude unused auto-configurations with
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, RabbitAutoConfiguration.class})if a service doesn't need DB or RabbitMQ.
- Remove
- Fine-tune JVM parameters:
- Set
Xmsequal toXmx(e.g.,-Xmx200m -Xms200m) to avoid JVM resizing the heap, which causes memory fluctuations. - Limit metaspace (where class metadata lives) with
-XX:MaxMetaspaceSize=128m -XX:CompressedClassSpaceSize=64m—this prevents it from eating up unallocated memory. - Use modern GC algorithms like G1GC (
-XX:+UseG1GC) or ZGC (for JDK 11+) to minimize pause times and stabilize memory usage.
- Set
- Optimize Spring Boot runtime:
- Enable lazy initialization with
spring.main.lazy-initialization=trueto only load beans when they're first needed, reducing startup and idle memory. - Disable unused Actuator endpoints (e.g., set
management.endpoints.web.exposure.include=health,infoinstead of exposing all). - Tune embedded container settings: For Tomcat, lower thread pool limits with
server.tomcat.max-threads=10andserver.tomcat.min-spare-threads=2to cut down on idle thread memory.
- Enable lazy initialization with
2. How to troubleshoot components/dependencies that use high memory?
You can use a mix of JVM tools and Spring-specific utilities to pinpoint culprits:
- Heap dump analysis:
- Generate a heap dump with
jmap -dump:format=b,file=heap.hprof <your-service-pid>, then open it with VisualVM (built into JDK) or JProfiler. Look for large object instances (e.g., cached JPA entities, RabbitMQ connection pools) or unexpected class loads. - Use Spring Boot Actuator's
/actuator/heapdumpendpoint to download a dump directly from the running service (make sure this endpoint is secured in production).
- Generate a heap dump with
- Dependency auditing:
- Run
mvn dependency:tree(or./gradlew dependenciesfor Gradle) to spot redundant or heavy dependencies. For example, some starters pull in unused transitive dependencies you can exclude.
- Run
- Real-time monitoring:
- Use
jstat -gc <pid>to track GC activity over time—frequent full GCs might indicate memory leaks or misconfigured heap sizes. - Try Arthas (a Java diagnostic tool) to run
heapdumportracecommands to see which methods are creating excessive objects.
- Use
3. Is memory fluctuation caused by the embedded Tomcat?
This is a very likely culprit—here's why and how to verify:
- Embedded Tomcat maintains a thread pool, and even idle threads take up memory for their stacks and context. When requests come in (even health checks), Tomcat may spin up threads, and when idle, it keeps some alive per
min-spare-threadssettings, causing memory to rise and fall as threads are created/destroyed or GC'd. - Tomcat also uses internal buffers (for request/response processing) and class loaders that can contribute to memory swings.
- How to test:
- Swap Tomcat for a lighter container like Undertow: Replace
spring-boot-starter-webwithspring-boot-starter-undertowand observe if fluctuations calm down. - Tune Tomcat's thread pool aggressively: Set
server.tomcat.max-threads=5andserver.tomcat.min-spare-threads=1to reduce idle thread overhead. - Note: Normal JVM GC activity will also cause minor memory fluctuations—if the swings are small (tens of MB), that's expected. Only worry if it's jumping hundreds of MB or causing OOM errors.
- Swap Tomcat for a lighter container like Undertow: Replace
4. Will exporting to WAR and deploying to JBoss/Tomcat reduce memory usage?
Yes, but it depends on your setup—here's the breakdown:
- Memory savings come from shared resources:
- Multiple WARs on a single app server share the same JVM and container class loader. This means common libraries (like Spring Core, Eureka Client) are loaded once instead of 7 times (once per JAR), cutting down significantly on metaspace and heap memory from duplicate class loads.
- Shared thread pools (managed by the app server) are more efficient than each JAR running its own embedded Tomcat thread pool—you avoid redundant idle threads across services.
- Caveats to consider:
- Dependency version conflicts: If your services use different versions of the same library, you might hit class loading issues (e.g., NoClassDefFoundError or LinkageError).
- Single point of failure: A crash in the app server affects all your services, whereas JARs run as separate processes and isolate failures.
- Less granular control: You can't set unique JVM parameters per service—all WARs share the same
JAVA_OPTSfor the app server.
内容的提问来源于stack exchange,提问作者Krish
相关产品推荐
相关产品推荐

