吞吐量调优核心是优先选用parallel gc,因其多线程并行回收、无并发开销、cpu利用率高,配合-xx:gctimeratio=19可稳定控制gc时间占比≤5%,适用于后台批处理等不敏感单次停顿但要求整体完成快的场景。

吞吐量调优的核心是让 JVM 在单位时间内执行尽可能多的用户代码,减少 GC 占用时间。这意味着要优先选能压低 GC 总耗时、提升 CPU 利用率的回收器,而不是追求单次停顿短。
吞吐量优先场景适合 Parallel GC
后台批处理、日终对账、ETL 清洗、报表生成等任务,不敏感于单次卡顿,但要求“一小时内跑完 100 个任务”,这类场景 Parallel GC 是最直接有效的选择。
- 它默认启用多线程并行回收年轻代和老年代(Parallel Scavenge + Parallel Old),无并发协调开销,CPU 利用率高;
- 通过 -XX:+UseParallelGC 启用,JDK 8 及之后版本默认就是它;
- 配合 -XX:GCTimeRatio=19(即 GC 时间占比 ≤5%)可明确表达吞吐目标,比硬设
MaxGCPauseMillis更稳定可靠; - 堆越大、CPU 核心越多,优势越明显;物理核数 ≥8 时,可显式设 -XX:ParallelGCThreads=8 避免线程争抢。
别为“新”而换 G1,除非你真需要软实时停顿
G1 的设计目标是平衡吞吐与可预测停顿,不是单纯吞吐最大化。在纯吞吐场景下,它的 Region 管理、并发标记、混合回收等机制反而引入额外开销。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 如果业务 SLA 只要求“整体完成快”,没有 P99
- 强行给 G1 设 -XX:MaxGCPauseMillis=50,会导致频繁并发标记、过早混合回收,CPU 占用升高、Minor GC 更密,最终吞吐可能下降;
- 只有当你同时需要“高吞吐 + 停顿可控在 200~400ms”时,G1 才值得引入——这是它真正的定位。
小内存或轻量服务用 Serial GC 更干净
不是所有“吞吐优先”都意味着大堆多核。嵌入式网关、本地开发服务、单核 ARM 设备上的 Spring Boot demo,堆常 ≤512MB,这时 Parallel GC 的线程调度反而成负担。
- -XX:+UseSerialGC 启用后,新生代(DefNew)和老年代(SerialOld)全程串行,无锁、无同步、无跨线程通信,开销最低;
- 适合内存受限又需长期稳态运行的场景,比如容器中限制 512MB 的 API 网关;
- 验证是否生效:看 GC 日志里是否出现
DefNew和Tenured,而非PSYoungGen或G1 Young Generation。
调优前先看真实数据,别靠参数猜
无论选哪个回收器,上线前必须采集真实负载下的行为特征:
- 加参数 -Xlog:gc*:file=gc.log:time,tags,level(JDK 11+)或 -verbose:gc -XX:+PrintGCDetails 记录日志;
- 重点关注三项:Minor GC 频率与平均耗时、Full GC 是否发生、老年代使用率是否缓慢爬升(提示潜在内存泄漏);
- 用 jstat -gc
实时观察 Eden/Survivor/老年代水位变化,确认对象晋升是否合理; - 吞吐调优最终要看指标:应用总耗时、CPU user 时间占比、GC 时间占比 —— 而不是某条参数是否“看起来很专业”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










