跳转到内容

调优目标与参数设定

用途:给一个服务定 GC 与内存参数,并知道每个参数在优化什么

三个必须写下来的数字:

  1. 延迟目标:应用 P99/P999 RT 上限,以及可接受的单次最大停顿。
  2. 吞吐目标:GC 时间占比上限(在线服务常取 < 3-5%)。
  3. 容量目标:单机 QPS、实例数、容器内存限制。

没有目标就没有“调好了”的判断依据,只能瞎试参数。

参数 作用 设定建议
-Xms / -Xmx 堆初值/上限 在线服务常设相同,避免运行期扩缩抖动;容器内留出栈/元空间/堆外余量
-XX:MaxMetaspaceSize 元空间上限 显式设置,防类加载泄漏吃满内存
-XX:MaxDirectMemorySize 堆外上限 使用 NIO/Netty 时必须显式限
-Xss 线程栈大小 线程多时下调(如 512k),但递归深的应用慎用
-XX:MaxGCPauseMillis G1 停顿目标 200ms 起步,按应用 P99 反推,不要盲目调小
-XX:InitiatingHeapOccupancyPercent 并发标记触发阈值 默认 45;晋升波动大时下调
-XX:+UseStringDeduplication 字符串去重(G1) 字符串密集且内存吃紧时评估
-Xlog:gc* GC 日志 生产必开,输出到文件并轮转
-XX:+HeapDumpOnOutOfMemoryError OOM 时 dump 生产开启,注意磁盘与 dump 体积

调优顺序(性价比从高到低)

「调优顺序(性价比从高到低)」小节链接
  1. 修代码:减少分配速率(对象复用、避免装箱与临时集合、字符串拼接、日志格式化)、修内存泄漏、避免大对象。
  2. 给对内存:堆大小与容器限制匹配,避免过小的 Young 区或过大的堆导致单次回收耗时。
  3. 选对收集器:按延迟/吞吐目标选 G1 / Parallel / ZGC。
  4. 微调参数:停顿目标、IHOP、Region 大小、并行线程数。
  5. 架构层:拆分实例、隔离大任务、把批处理与在线服务分开部署。

经验判断:绝大多数“GC 调优”的收益来自第 1 步,参数只是把系统能力对齐到代码的真实分配行为。

  • 压测固定流量,对比修改前后的:GC 频率、单次停顿 P99、总 GC 时间占比、应用 P99 RT、晋升速率。
  • 至少覆盖 30 分钟真实流量曲线(含峰值与低谷),避免只看稳态。
  • 保留 GC 日志与火焰图,做前后对照,而不是“感觉变快了”。
误区 修正
网上抄一套“最佳参数” 参数必须对应自身分配行为与目标
堆越大越好 单次回收成本与内存占用同步上升,容器 OOMKill 风险增加
只看 Young GC 次数 关注总停顿占比与尾停顿
忽略分配速率 停顿问题的根因常在分配,不在回收
生产直接改参数不灰度 逐实例灰度并保留回滚
  • OpenJDK HotSpot VM Options 与 GC Tuning 指南
  • 《Java 性能权威指南》(Scott Oaks)
  • Nitsan Wakart 关于分配速率与 GC 的公开文章