一、为什么要理解垃圾收集器的代际演进
很多工程师对 GC 的认知停留在「STW 越小越好、吞吐量越大越好」的口号层面,一到生产环境就凭感觉堆参数。实际上,不同垃圾收集器的核心差异在于内存布局、对象标记/复制算法、并发阶段与暂停模型的组合方式。同样一份负载,在 CMS 上表现良好的配置原封不动搬到 ZGC 上反而会拖慢吞吐量;反过来,一个「大堆、低延迟」的诉求如果硬套 Parallel Scavenge,几乎注定要经历周期性长暂停。
理解演进,本质上是理解一个约束条件的逐步解除过程:CMS 试图在分代假设下并发做掉大部分标记与清除,但受限于「标记-清除」的内存碎片与「并发标记-再标记」的漏标补偿;G1 用 Region 化布局 + 可预测停顿的增量回收 + 复制式整理,把停顿从「堆大小相关」拉回到「回收集大小相关」;ZGC 则用染色指针与读屏障,把「并发整理」推向极致,让停顿收敛到与堆大小基本无关。 这一路走来,每一代都在解决上一代最痛的短板,也都引入了新的运维复杂度。
2022/3/19大约 12 分钟