GC调优需在吞吐量、停顿时间、内存占用三者间权衡取舍:吞吐优先选Parallel GC并增大堆,但停顿和内存上升;延迟优先用G1或ZGC,但吞吐下降、内存开销增加;内存受限时需减小堆并调高新生代比例,但GC频率和Full GC风险上升。

GC调优没有“全能解”,吞吐量、停顿时间、内存占用三者构成典型的权衡三角。你无法同时把三者都压到最优,必须根据应用类型明确主次——选两个重点保,另一个就得适当让步。
吞吐量优先时,停顿和内存往往要妥协
高吞吐场景(如离线报表生成、批量ETL)更看重单位时间内完成多少任务。这时常用 Parallel GC,配合 -XX:GCTimeRatio=99 显式要求 GC 时间占比 ≤1%。但代价是:单次 GC 停顿可能升至 200ms 甚至更高;为减少 GC 频率而增大堆(比如从 4G 调到 8G),又直接推高内存占用。
- 增大堆可降低 GC 次数,但单次扫描范围变大,停顿易拉长
- 并行线程数设得过高,可能争抢 CPU,反而拖慢应用线程
- 老年代空间宽松后,对象晋升变慢,Full GC 虽少,但一旦触发更难收场
停顿时间优先时,吞吐和内存控制难度上升
对延迟敏感的系统(如游戏服务器、支付接口)必须把单次 STW 控制在 100ms 内。G1 用 -XX:MaxGCPauseMillis=100 主动约束,ZGC 更进一步压到 10ms 级别。但这需要并发标记、并发整理等复杂机制,GC 线程持续消耗 CPU,挤占应用计算资源,吞吐自然下降;同时为保障低延迟,堆不能太大,区域划分更细,元数据开销增加,实际内存效率反而不如大块连续堆。
- G1 的 Region 大小(-XX:G1HeapRegionSize)太小会增碎片,太大又影响停顿可控性
- ZGC 要求堆大小为 2MB 对齐,且软堆上限(-XX:SoftMaxHeapSize)需手动设,否则可能浪费预留空间
- 频繁的小规模回收虽缩短单次停顿,却提高 GC 总次数,CPU 时间被更多切片占用
内存占用优先时,停顿与吞吐通常双双承压
嵌入式或容器化环境常受限于固定内存配额(如 Docker 限制 512MB)。此时堆必须设小(-Xmx512m),新生代比例调高(-XX:NewRatio=1)加速短命对象回收。但后果明显:Minor GC 极其频繁,应用线程不断被打断;小堆下对象更容易晋升到老年代,触发 Full GC 的风险上升;GC 总耗时占比升高,吞吐直线下滑。
- 堆小于 1G 时,Parallel GC 可能比 G1 更稳定,因后者 Region 管理开销占比变高
- 避免大对象直接进老年代(如 byte[] > 512KB),否则一次分配就可能触发 Mixed GC
- 元空间(Metaspace)未设上限时,动态类加载容易悄悄吃掉数百 MB 内存
不复杂但容易忽略:这三个目标不是静态参数,而是运行态表现。同一套 JVM 参数,在流量高峰和低谷时,吞吐、停顿、内存压力的分布可能完全不同。真正有效的调优,一定建立在真实负载下的 GC 日志分析和周期性回归验证之上。

















