一、为什么要进行 JVM 调优?(目标驱动)
不要为了调优而调优,调优通常为了解决以下三类问题或达成特定目标:
- 降低延迟(Low Latency):
- 场景:互联网高并发应用(如电商、支付)。
- 目标:减少 GC 停顿时间(STW),确保接口响应时间(RT/TP99)达标,避免用户感觉卡顿。
- 提高吞吐量(High Throughput):
- 场景:后台批处理任务、大数据计算。
- 目标:让 CPU 更多时间用于执行业务代码,减少 GC 时间占比(如低于 5%),单位时间内处理更多请求。
- 解决内存异常:
- 场景:频繁出现 OutOfMemoryError(OOM)或内存泄漏。
- 目标:消除内存溢出,合理利用物理内存,避免因内存不足导致服务崩溃。
二、JVM 调优的详细步骤(How)
JVM 调优不是拍脑袋改参数,而是一个严谨的闭环过程。
第一步:建立性能基线(Baseline)
在做任何改动前,先记录当前系统的状态。
- 开启 GC 日志:这是最重要的依据。添加参数(以 JDK 8 为例):
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc.log - 收集数据:使用 jstat、jmap 或监控系统(如 Prometheus + Grafana)记录当前的堆内存使用率、GC 频率、停顿时间等指标。
第二步:监控与问题诊断(Diagnosis)
利用工具分析系统瓶颈,确定是'内存不够'还是'GC 策略不对'。
- 实时监控(jstat):
- 命令:
jstat -gcutil 1000 - 看什么:频繁的 YGC(新生代回收)可能意味着对象分配过快;频繁的 FGC(老年代回收)则是性能杀手,意味着系统可能面临内存压力或泄漏。
- 命令:
- 线程分析(jstack):
- 命令:
jstack > thread_dump.txt - 看什么:排查死锁、线程阻塞或 CPU 占用过高的原因。
- 命令:
- 内存快照分析(jmap + MAT):
- 命令:
jmap -dump:format=b,file=heap.hprof - 看什么:当发生 OOM 或怀疑内存泄漏时,导出堆转储文件,使用 MAT(Memory Analyzer Tool)分析哪些对象占用了大量内存,以及为什么它们没有被回收。
- 命令:
第三步:调整 JVM 参数(Optimization)
根据诊断结果,针对性地调整参数。以下是核心参数调整策略:
- 调整堆内存大小(-Xms, -Xmx)
- 操作:将初始堆大小和最大堆大小设为一致(如
-Xms4g -Xmx4g)。 - 目的:避免 JVM 动态扩容/缩容带来的性能抖动。
- 建议:堆大小通常设置为物理内存的 60%-80%,但不要超过 32GB(避免指针压缩失效)。
- 操作:将初始堆大小和最大堆大小设为一致(如
- 选择合适的垃圾回收器(GC Collector)
- 追求吞吐量:使用 Parallel GC(
-XX:+UseParallelGC)。 - 追求低延迟:使用 G1 GC(
-XX:+UseG1GC,JDK 8 常用)或 ZGC(-XX:+UseZGC,JDK 11+,停顿时间极短)。 - 微服务/大内存应用:推荐 G1,它能设置预期停顿时间(
-XX:MaxGCPauseMillis=200)。
- 追求吞吐量:使用 Parallel GC(


