关键在于匹配应用特征,Web/API用G1(-XX:+UseG1GC -XX:MaxGCPauseMillis=200)并固定堆(-Xms4g -Xmx4g),批处理选Parallel GC,超低延迟用ZGC,小内存用Serial GC;堆、新生代、元空间等参数须显式固定并协同调优。

合理配置 JVM 垃圾回收器参数,关键不是堆得大、停顿短,而是让 GC 行为贴合你的应用真实特征——对象生命周期、并发压力、响应要求和硬件资源。参数之间要协同,不能孤立调一个就以为万事大吉。
先按场景选对回收器
回收器不是越新越好,也不是默认最稳:
-
Web/API 类服务(4GB~64GB 堆,停顿敏感):用 G1,加
-XX:+UseG1GC -XX:MaxGCPauseMillis=200。目标值不是硬性保证,但能引导 G1 调整回收节奏;别忘了配-Xms4g -Xmx4g固定堆大小。 -
后台批处理(吞吐优先,可接受秒级停顿):用 Parallel GC,
-XX:+UseParallelGC -XX:+UseParallelOldGC,再设-XX:MaxGCPauseMillis=1000反而可能拖慢整体吞吐,不如不设。 -
超低延迟场景(JDK ≥ 11,堆 > 8GB):ZGC 更合适,
-XX:+UseZGC -Xmx16g即可启用,它不依赖新生代比例,也不需要调NewRatio或SurvivorRatio。 -
小内存或单核环境(≤ 2GB):Serial GC 开销最小,
-XX:+UseSerialGC就够用,别强行上 G1。
堆与分代参数要“显式固定”
靠 JVM 自动推算容易出偏差,尤其在流量波动时:
-
堆大小必须固定:
-Xms4g -Xmx4g(例如),避免扩容缩容引发卡顿;生产中最大堆建议 ≤ 物理内存的 50%~70%,给系统缓存留空间。 -
新生代别靠 NewRatio 猜:直接用
-Xmn1.5g(占总堆约 3/8)更可控;电商类瞬时对象多,可提高到 40%;缓存类长生命周期对象多,可降到 25%。 -
Survivor 区要能“托住”对象:默认
-XX:SurvivorRatio=8(Eden:S0:S1 = 8:1:1),若日志里频繁出现to-space overflow,说明 Survivor 太小,可调成6或4。 -
晋升阈值要匹配存活时间:
-XX:MaxTenuringThreshold=6适合多数 Web 请求;若 MAT 分析发现大量对象活过 10 次 GC,再考虑调高,但别盲目设到 15。
元空间和 GC 日志不能省
这两个参数常被忽略,却是定位问题的关键入口:
-
元空间必须设上限:Spring Boot、动态代理多的应用极易因类加载失控触发 Full GC,
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m是较稳妥的起点。 -
GC 日志是调优的眼睛:用
-Xlog:gc*:file=gc.log:time,uptime,pid,tags(JDK 10+)或-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log(旧版),重点看YGC 频率、FGC 次数、晋升大小和停顿时间分布。 -
别只盯“有没有 GC”,要看“健不健康”:吞吐量(
应用运行时间 / (应用运行时间 + GC 时间))建议 ≥ 95%;单次 Full GC 超过 1s 或每天发生多次,就得查根因。
避开常见运行环境陷阱
再好的参数,跑在错的环境里也白搭:
-
禁用 swap:Linux 上 swap 会极大延长 GC STW 时间,
swapoff -a并注释/etc/fstab中 swap 行。 -
关闭透明大页(THP):CentOS/RHEL 默认开启,会导致 G1/ZGC 性能抖动,
echo never > /sys/kernel/mm/transparent_hugepage/enabled。 -
线程栈别过大:默认
-Xss1m在高并发下易耗尽虚拟内存,-Xss256k更稳妥,除非你真有深度递归。 -
容器部署注意 cgroup 限制:JDK 10+ 支持自动识别容器内存限制,但老版本需加
-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0。


















