多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

12-JVM 调优方法论与参数速查

12-JVM 调优方法论与参数速查 本篇是「JVM 与性能调优系列」第 12 篇系列收尾。前面 11 篇你都看了但真到线上还是乱。因为缺一套「先想清楚再动手」的方法论。这篇把 JVM 调优收成一张图、一张表以后遇事照着走。一、调优的第一原则别调优听起来反直觉但最重要。80% 的「性能问题」根本不是 JVM 参数问题而是代码或架构问题无脑全表查询、缓存击穿、N1、线程池配错、同步阻塞。这些问题靠-Xmx翻倍是盖不住的反而掩盖了病灶。而且 JVM 默认值尤其 JDK 9 的 G1 自适应已经相当聪明。对新项目先用默认 G1/ZGC跑压测看指标真有瓶颈再动参数。调优是「验证假设」不是「堆参数碰运气」。二、问题分类决策树遇事先归类再动手吞吐不够→ 看 Parallel或调大堆、查计算热点火焰图延迟高停顿长→ G1 调MaxGCPauseMillis或上 ZGC内存溢出→ 走第 10 篇 OOM 流程先分 Java OOM / OS KillCPU 高→ 走第 11 篇死循环 / 频繁 GC / 死锁启动慢 / 元空间涨→ 看类加载、-XX:MaxMetaspaceSize分类错了工具就用错——比如 CPU 高是 GC 引起的你却在代码里找死循环。三、一套通用调优流程闭环定目标 → 建基线 → 找瓶颈 → 改一处验一处 → 固化告警定目标吞吐优先还是延迟优先量化指标如「P99 停顿 200ms吞吐 98%」建基线开 GC 日志 压测统计当前吞吐量、平均/最大停顿、Full GC 频率找瓶颈用日志、火焰图、Arthas 定位最制约指标的那一环改一处验一处只动一个参数压测对比基线。有效固化无效回滚换假设固化 告警把参数写进部署配置把关键指标老年代、直接内存、线程数接告警四、参数速查表按用途分组内存-Xms / -Xmx 堆初始/最大生产设相等 -XX:MaxMetaspaceSize 元空间上限 -XX:MaxDirectMemorySize 直接内存上限收集器-XX:UseG1GC G1JDK9 默认 -XX:UseZGC ZGC大堆低延迟 -XX:UseSerialGC / -XX:UseParallelGC 朴素场景G1 关键-XX:MaxGCPauseMillis 停顿目标 -XX:InitiatingHeapOccupancyPercent 触发 Mixed GC 的老年代占用默认45 -XX:G1HeapRegionSize Region 大小 -XX:G1ReservePercent 预留防晋升失败默认10ZGC 关键-XX:SoftMaxHeapSize 软上限空闲时归还 OS诊断强烈建议常开-Xlog:gc* 统一 GC 日志 -XX:HeapDumpOnOutOfMemoryError 出 OOM 自动留堆快照 -XX:HeapDumpPath/path五、监控与告警清单调完不是结束是开始监控老年代使用率持续 80% 预警防 Full GCFull GC 频率 / 最大停顿1s 立刻查直接内存、线程数防 OS KillSafePoint 耗时过长说明代码里有长循环不进安全点工具链Prometheus Grafana 采集 JMXArthas 在线急救火焰图async-profiler定位热点。六、JDK 版本选择JDK 8仍是很多公司的稳定基线但 CMS 已移除、ZGC 不可用JDK 17 / 21LTS是新建项目的甜点区ZGC 成熟、G1 更强、长期支持、性能更好升级有成本依赖兼容、测试但长远看新收集器和新特性带来的稳定性收益通常远超迁移投入七、系列总结12 篇串成一条线内存模型第1篇→ 对象布局2→ GC 算法3→ 分代4 → 收集器 Serial/Parallel5→ CMS6→ G17→ ZGC8 → GC 日志调优9→ OOM 排查10→ CPU/死锁11→ 方法论12从「内存长什么样」到「怎么查、怎么调」你现在有了完整的 JVM 坐标系。调优的本质从来不是背参数而是理解原理、用数据驱动、闭环验证。八、火焰图定位热点GC 和内存都正常但 CPU 高、吞吐上不去问题在业务代码本身的热点。这时用async-profiler抓火焰图# 采样 60 秒 CPU 火焰图asprof-d60-fflamegraph.htmlpid火焰图里最宽的那一层就是最耗时的调用栈。常见「热点」正则Pattern.compile写在循环里每次重建JSON 序列化大对象、反射调用未缓存无意义的深拷贝、重复计算这些靠 JVM 参数永远调不好只能改代码。火焰图是区分「JVM 问题」和「代码问题」的照妖镜。九、常见调优误区清单堆越大越好超过 32G 指针压缩失效对象头翻倍且大堆 Full GC 更慢MaxGCPauseMillis 设极小值反而频繁 GC、吞吐崩只在出事时调应在上线前压测定基线而非半夜救火照搬网上的「最优参数」别人 64G 堆的参数套到你 4G 堆上必然翻车忽视监控调完不设告警下次出问题又从零查起记住参数是手段指标是目标理解原理才是根本。十、调优 Checklist 速查一张贴墙清单覆盖绝大多数场景先用默认 G1/ZGC 跑压测确认真的有瓶颈开 GC 日志 HeapDumpOnOutOfMemoryError 留现场吞吐问题 → 看 Parallel / 堆大小 / 计算热点延迟问题 → 调 MaxGCPauseMillis / 上 ZGCOOM → 分 Java OOM / OS Kill按第 10 篇流程CPU 高 → 定死循环/频繁GC/死锁按第 11 篇流程一次只动一个参数前后压测对比固化参数 接告警形成闭环十一、从 0 到 1 建一套 JVM 监控没监控的调优是瞎子摸象。最小可行监控暴露指标-XX:UseG1GC配合 JMX-Dcom.sun.management.jmxremote或用 jmx_exporter采集Prometheus 拉 JMX 指标堆/各代/GC 次数耗时/线程数展示Grafana 画「堆使用率、GC 停顿 P99、Full GC 频率」三张核心图告警老年代 85%、Full GC 3 次/5 分、最大停顿 1s 触发告警急救Arthas 常备随时在线定位这套建起来你从「半夜被叫醒救火」变成「告警里提前看到趋势」运维体验天差地别。总结JVM 调优第一原则「别调优」先排除代码/架构问题再用默认收集器跑压测。遇事走决策树归类用「定目标→建基线→找瓶颈→改验→固化告警」闭环一次只动一个参数。把本文的速查表和告警清单存好下次线上抖动照着走就不慌。
返回列表