性能调优
Spring Boot 应用的性能调优涉及 JVM 层、应用层、框架层三个维度。JVM 底层原理参见 JVM 与 垃圾回收。
JVM 内存配置
Spring Boot 应用本质是运行在 JVM 上的进程,内存分区详见 JVM 内存结构。
堆内存
# 生产环境建议 Xms = Xmx,避免动态扩容带来的停顿
java -Xms2g -Xmx2g -jar app.jar
# 容器环境(Docker/K8s)使用比例,避免超出容器限制
java -XX:InitialRAMPercentage=50.0 \
-XX:MaxRAMPercentage=75.0 \
-jar app.jar元空间(Metaspace)
存放类元数据,无上限时可能持续增长(动态代理、JSP 场景):
-XX:MetaspaceSize=256m # 初始大小,达到后触发 GC
-XX:MaxMetaspaceSize=512m # 上限,防止无限增长详见 JVM - 方法区与元空间。
堆外内存(Direct Memory)
NIO、Netty 等使用堆外内存,不受 -Xmx 限制:
-XX:MaxDirectMemorySize=512m垃圾回收器选择
详见 垃圾回收 - 垃圾收集器。
| 场景 | 推荐收集器 | 参数 |
|---|---|---|
| 低延迟(API 服务) | G1 | -XX:+UseG1GC |
| 超低延迟(< 1ms) | ZGC | -XX:+UseZGC |
| 高吞吐(批处理) | Parallel | -XX:+UseParallelGC |
| 小内存(< 256m) | Serial | -XX:+UseSerialGC |
G1 调优(Spring Boot 默认推荐)
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200 # 目标停顿时间
-XX:G1HeapRegionSize=8m # Region 大小(1~32m,2 的幂)
-XX:G1NewSizePercent=20 # 新生代最小占比
-XX:G1MaxNewSizePercent=40 # 新生代最大占比
-XX:InitiatingHeapOccupancyPercent=45 # 触发并发标记的堆占用阈值ZGC(Java 17+ Spring Boot 3.x 推荐)
-XX:+UseZGC
-XX:SoftMaxHeapSize=6g # 软上限,GC 尽量不超过此值
-XX:ZCollectionInterval=5 # 定期 GC 间隔(秒)GC 日志与分析
# 开启 GC 日志(Java 9+)
-Xlog:gc*:file=logs/gc.log:time,uptime,level,tags:filecount=5,filesize=20m
# 打印 GC 详情(Java 8)
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:logs/gc.logGC 日志分析工具:
- GCEasy:在线分析,可视化 GC 停顿、吞吐量、内存趋势
- GCViewer:桌面工具,离线分析
- Actuator
/actuator/metrics:查看jvm.gc.pause指标,详见 Actuator 监控
GC 调优原则参见 垃圾回收 - GC 调优思路。
内存泄漏排查
常见原因
| 原因 | 典型场景 |
|---|---|
| 静态集合持续增长 | static Map 作缓存但不清理 |
| 未关闭资源 | 数据库连接、IO 流未 close |
| 内部类持有外部引用 | 匿名类、Lambda 捕获大对象 |
| ThreadLocal 未 remove | 线程池复用线程时残留 |
| 缓存无过期策略 | 本地缓存无限增长 |
| 监听器未注销 | 事件监听器、观察者未移除 |
排查流程
# 1. 观察堆内存趋势(持续上涨不回落 → 疑似泄漏)
# 通过 Actuator 查看
curl http://localhost:8080/actuator/metrics/jvm.memory.used
# 2. 触发 Full GC 后查看存活对象
jcmd <pid> GC.run
jmap -histo <pid> | head -30 # 按实例数排序,找异常类
# 3. 生成堆快照
jmap -dump:format=b,file=heap.hprof <pid>
# 或配置自动 dump(OOM 时)
# -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap.hprof
# 4. 分析堆快照
# MAT(Eclipse Memory Analyzer):找 Retained Heap 最大的对象
# VisualVM:对象引用链追踪
# JProfiler / ArthasArthas 在线诊断
# 启动 Arthas
java -jar arthas-boot.jar <pid>
# 查看内存
memory
# 查看 GC 信息
gc
# 找哪个类实例最多
classloader -a # 查看类加载器
heapdump /tmp/dump.hprof # 导出堆快照
# 追踪方法调用耗时
trace com.example.UserService getUser
watch com.example.UserService getUser returnObjSpring Boot 应用层调优
连接池
详见 连接池配置。
spring:
datasource:
hikari:
maximum-pool-size: 20 # CPU 核数 × 2 + 磁盘数,压测确定
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
leak-detection-threshold: 60000 # 连接泄漏检测阈值线程池
详见 异步与线程池。
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
executor.setQueueCapacity(500);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("app-async-");
executor.setRejectedExecutionHandler(new CallerRunsPolicy());
return executor;
}缓存
// 避免重复查询数据库
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}懒加载
spring:
main:
lazy-initialization: true # 启动时不初始化所有 Bean,按需加载
# 加快启动速度,但首次请求略慢详见 延迟加载。
数据库查询优化
详见 JPA 与 Hibernate、MyBatis-Plus。
// 只查需要的字段,避免 SELECT *
@Query("SELECT new com.example.dto.UserDTO(u.id, u.name) FROM User u WHERE u.id = :id")
Optional<UserDTO> findDtoById(@Param("id") Long id);
// 分页查询,避免全表扫描
Page<User> findByDept(String dept, Pageable pageable);
// 批量操作,避免 N+1
@BatchSize(size = 100)
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;启动速度优化
# 排查启动慢的 Bean
-Dspring.main.lazy-initialization=true
# 分析启动各阶段耗时(Spring Boot 2.4+)
-Dspring.startup.duration.enabled=true// 记录启动耗时
@SpringBootApplication
public class App {
public static void main(String[] args) {
StopWatch sw = new StopWatch();
sw.start();
SpringApplication.run(App.class, args);
sw.stop();
System.out.println("启动耗时: " + sw.getTotalTimeSeconds() + "s");
}
}原生镜像编译(极致启动速度):详见 GraalVM 原生编译。
监控指标
通过 Actuator 暴露 JVM 指标,配合 Prometheus + Grafana 监控:
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
export:
prometheus:
enabled: true关键指标:
| 指标 | 说明 |
|---|---|
jvm.memory.used | 各区域内存使用量 |
jvm.gc.pause | GC 停顿时间 |
jvm.gc.memory.promoted | 晋升老年代的数据量 |
jvm.threads.live | 活跃线程数 |
hikaricp.connections.active | 活跃数据库连接数 |
http.server.requests | 请求耗时分布 |
JVM 参数完整模板
java \
# 堆内存
-Xms2g -Xmx2g \
# 元空间
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \
# 堆外内存
-XX:MaxDirectMemorySize=256m \
# GC
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
# GC 日志
-Xlog:gc*:file=logs/gc.log:time,uptime:filecount=5,filesize=20m \
# OOM 自动 dump
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=logs/heap.hprof \
# JIT 优化(详见 JIT.md)
-XX:+TieredCompilation \
# 其他
-XX:+UseStringDeduplication \
-Dfile.encoding=UTF-8 \
-Duser.timezone=Asia/Shanghai \
-jar app.jar