Spring Boot启动慢主因是JVM初始化、类加载和自动配置叠加,优化需聚焦减少阻塞操作:禁用C2编译、跳过字节码验证、调小初始堆、关闭devtools、精简Starter并启用懒加载,配合诊断工具定位瓶颈。

Java 应用启动慢,往往不是代码本身问题,而是 JVM 初始化、类加载和框架自动配置层层叠加导致的。优化启动性能,关键在减少启动阶段的阻塞操作和冗余开销,而不是盲目调大内存或换 GC。
启动阶段核心瓶颈要先看清
JVM 启动到 main 方法执行,实际经历:JVM 进程加载 → 堆与 GC 初始化 → 类加载器加载主类 → 字节码验证 → 静态变量初始化 → 执行 main。其中最耗时的通常是:
- 大量类的加载与字节码验证(尤其 Spring Boot 自动配置扫描)
- 反射与注解解析(@Configuration、@Bean 等)
- JVM 自身初始化(如堆分配、GC 线程启动、JIT 编译器预热)
这些步骤无法跳过,但可以“轻量化”或“延迟化”。
用对 JVM 参数,直接砍掉可观启动时间
以下参数组合已在 Spring Boot、微服务等典型场景中验证有效(适用于 JDK 8–21):
立即学习“Java免费学习笔记(深入)”;
-Xms64m -Xmx512m
初始堆设小一点,避免启动时分配大堆带来的延迟;最大堆按需设,不追求“越大越好”。-XX:TieredStopAtLevel=1
禁用 C2 编译器(激进优化编译),让代码以解释模式或 C1 快速执行——启动阶段不需要高性能 JIT,省下编译等待时间。-noverify
跳过字节码验证(仅限可信环境,如私有云、CI/CD 构建镜像)。实测可减少 5%–15% 启动耗时,尤其类多时效果明显。-XX:+UseG1GC -XX:MaxGCPauseMillis=100
G1 在中小堆下启动更轻快;设置 pause 目标,促使 JVM 更早触发并发回收,避免后续卡顿影响“就绪感知”。-Dspring.profiles.active=prod -Dspring.devtools.restart.enabled=false
非开发环境务必关闭 devtools;指定明确 profile,避免 Spring 搜索和激活多个配置造成反射开销。
配合启动日志,定位真瓶颈点
光改参数不够,得知道哪一步拖了后腿:
-
加入诊断参数启动:
java -XX:+PrintCommandLineFlags \ -XX:+PrintGCApplicationStoppedTime \ -XX:+UnlockDiagnosticVMOptions \ -XX:+LogVMOutput \ -XX:LogFile=jvm-start.log \ -jar app.jar -
关注日志里两类时间:
-
Application stopped行:显示每次 STW(Stop-The-World)耗时,若某次超 200ms,说明类加载或初始化卡住了 -
Loaded X classes类似提示:结合-verbose:class可看具体加载了哪些类,排查无用 starter 或冗余依赖
-
-
推荐搭配工具:
-
jcmd <pid> VM.native_memory summary:查启动初期本地内存分配热点 - Async-Profiler 采样启动前 10 秒:生成火焰图,一眼看出
Class.forName、AnnotatedElementUtils等反射调用是否扎堆
-
依赖与框架层面同步精简
JVM 参数只是半边腿,另一半靠应用瘦身:
- 移除未使用的 Starter(如不用 WebSocket 就删
spring-boot-starter-websocket) - 使用
@ConditionalOnClass或@ConditionalOnMissingBean控制自动配置加载范围 - 对非核心模块启用
@Lazy注解,推迟 Bean 初始化到首次调用 - 构建时启用
spring-aot(Spring Boot 3.2+)或native-image(GraalVM),把反射元数据提前固化,彻底绕过运行时扫描
不复杂但容易忽略



















