JVM GC必然触发Stop-The-World停顿,非可选行为。Minor GC停顿几至几十毫秒,Full GC可达数百毫秒至数秒,ZGC/Shenandoah仍有极短元数据扫描暂停。

JVM 垃圾回收器(GC)不是后台静默服务,它会直接干预代码运行——暂停线程、消耗CPU、改变内存布局,进而影响响应时间、吞吐量和稳定性。
触发停顿(Stop-The-World)是核心干扰
几乎所有主流GC(包括Serial、Parallel、CMS、G1)在执行关键阶段时,必须暂停全部用户线程。这不是可选行为,而是保证对象图一致性的必要手段。
- Minor GC 通常停顿几毫秒到几十毫秒,对高并发Web接口已可能造成超时(如RT从50ms突增至200ms);
- Full GC 停顿可达数百毫秒甚至数秒,用户明显感知卡顿,RPC调用频繁失败,分布式系统中节点可能被心跳机制误判下线;
- ZGC 和 Shenandoah 虽宣称“几乎不STW”,但仍有极短的元数据扫描暂停(通常
CPU与内存资源被动态抢占
GC不是零开销操作:它要遍历对象图、计算引用关系、移动或复制对象、整理内存空间——这些都消耗真实CPU周期和内存带宽。
- Parallel GC 启动多线程并发清理,会显著拉升CPU使用率,在容器化环境中可能触发CPU节流,拖慢业务线程;
- G1 在混合回收阶段需同时处理老年代分区和年轻代,若并发标记未及时完成,会退化为Full GC,导致资源双重挤压;
- 频繁分配大对象(如byte[]缓存、JSON解析结果)会加速Eden区耗尽,间接提高GC频率,形成“分配→GC→更难分配”的恶性循环。
内存布局变化引发隐性性能抖动
GC不仅释放内存,还重排存活对象位置。这种变动会影响CPU缓存局部性、对象访问延迟,甚至触发TLB miss。
- 标记-整理(如Serial Old、Parallel Old)将对象向一端压缩,虽消除碎片,但大量对象迁移带来额外拷贝开销;
- 标记-清除(如CMS)保留碎片,当后续需分配连续大块内存(如nio direct buffer)时,可能因找不到足够空闲页而提前触发另一次GC;
- 新生代Survivor区的复制算法虽高效,但对象年龄增长、跨代引用检查(Remembered Set)维护等,都会增加每次Minor GC的固定成本。
不可预测性放大系统风险
GC时机由堆占用率、对象晋升速率、并发标记进度等动态因素决定,无法精确控制。这使得性能问题难以复现和压测。
- 相同代码在不同负载下GC行为差异巨大:低QPS时可能数分钟才一次Minor GC,高QPS下每秒多次;
- 某些GC策略(如G1的预测模型)依赖历史数据,冷启动或流量突增时预测失准,易引发意外Full GC;
- System.gc()调用虽为建议,但部分JVM实现(尤其Server模式)会立即响应,导致关键路径上出现非预期停顿。

















