刚部署的 Spring Boot 应用占用较多内存是常见现象,主要原因包括以下几个方面:
1. JVM 默认堆内存设置较大
Spring Boot 底层运行在 JVM 上,而 JVM 的默认堆内存大小会根据物理内存自动调整。例如:
- 如果服务器有 8GB 内存,JVM 可能默认分配
1/4(即 2GB)作为最大堆(-Xmx)。 - 即使应用实际使用很少,操作系统也会看到较高的“虚拟”内存占用。
✅ 解决方案:
手动限制 JVM 堆内存,例如:
java -Xms256m -Xmx512m -jar your-app.jar
或通过环境变量:
export JAVA_OPTS="-Xms256m -Xmx512m"
java $JAVA_OPTS -jar your-app.jar
2. Spring Boot 自动配置和依赖加载
Spring Boot 遵循“约定优于配置”,会自动加载大量 Starter 组件(如 Web、数据源、安全等),即使你没有使用它们。
- 每个自动配置类都会被加载到内存中。
- 所有 Bean 在启动时被创建并注册到 IoC 容器。
- 使用了较多 Starter(如
spring-boot-starter-web,spring-boot-starter-data-jpa,spring-boot-starter-security等)会显著增加内存开销。
✅ 优化建议:
- 移除不必要的 Starter 依赖。
- 使用
@ConditionalOn...注解或条件化配置减少无用 Bean。 - 使用
--debug启动参数查看哪些自动配置被启用。
3. 嵌入式服务器(如 Tomcat)的开销
Spring Boot 默认内嵌 Tomcat、Jetty 或 Undertow,这些服务器本身也需要内存来初始化线程池、连接器等组件。
- Tomcat 默认启动多个工作线程(通常 10+)。
- 即使没有请求,这些线程和相关对象也占用内存。
✅ 可选方案:
- 切换为更轻量的服务器(如 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> </exclusion> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> - 调整服务器线程数:
server.tomcat.threads.max=50 server.tomcat.threads.min-spare=5
4. 类加载和元空间(Metaspace)占用
Spring Boot 应用包含大量类(尤其是使用了 Lombok、Spring Data JPA、Hibernate 等),这些类会被加载到 Metaspace 区域。
- 元空间用于存储类的元数据,默认不限上限(受系统内存限制)。
- 类越多,Metaspace 占用越高。
✅ 控制方式:
-XX:MaxMetaspaceSize=256m
5. 日志框架和其他监控组件
如果引入了:
- Spring Boot Actuator
- Prometheus + Micrometer
- 分布式追踪(如 Sleuth)
- 日志框架(Logback、Log4j2)
这些组件在启动时会预加载大量类和线程,增加内存消耗。
✅ 建议:
- 生产环境按需开启 Actuator 端点。
- 避免引入不必要的监控依赖。
6. 容器化部署中的认知偏差
在 Docker 中,docker stats 显示的内存可能包括:
- JVM 堆外内存(Direct Memory、Code Cache、Thread Stacks)
- Native 内存(JIT 编译、GC 等)
JVM 并不总是及时向操作系统释放内存,导致“看起来”占用高。
✅ 建议:
使用 JDK 8u131+ 或 JDK 10+ 支持的容器感知内存:
-Djdk.lang.Process.launchMechanism=OOME -XX:+UseContainerSupport
并配合:
--memory=512m
在 Docker 中限制容器内存。
7. 冷启动与后续表现
刚启动时,Spring Boot 会进行大量反射、X_X生成(AOP)、Bean 初始化,导致短暂高内存使用。稳定后通常会下降。
✅ 观察建议:
使用 jstat、jconsole、VisualVM 或 Prometheus + Micrometer 监控长时间运行后的实际内存趋势。
总结:如何降低内存占用?
| 措施 | 示例 |
|---|---|
| 限制 JVM 堆内存 | -Xms256m -Xmx512m |
| 减少不必要的 Starter | 移除未使用的 starter-* 依赖 |
| 使用轻量 Web 服务器 | 改用 Undertow |
| 控制 Metaspace | -XX:MaxMetaspaceSize=256m |
| 开启容器支持 | -XX:+UseContainerSupport |
| 关闭调试功能 | 设置 spring.main.banner-mode=off |
🔍 诊断工具推荐:
jps+jstat -gc <pid>查看 GC 和内存分布jmap -heap <pid>查看堆详情jcmd <pid> VM.native_memory(需开启)查看 native 内存- Spring Boot Actuator 的
/actuator/metrics/jvm.memory.used
如果你提供具体的内存占用数值、JVM 版本、依赖列表和启动参数,我可以进一步帮你分析优化。
云小栈