面试必问:Java 21中垃圾收集器的演进点
Java21垃圾收集器围绕低延迟、可预测性和大堆适配取得实质性突破。G1正式引入代际G1,显式维护年轻代与老年代边界,优化回收效率。ZGC实现亚毫秒级停顿,通过并发线程栈处理彻底降低STW时间。并发标记与混合回收引入智能调度。G1仍为默认,ZGC成为延迟敏感与大堆场景首选。
聊到Ja va 21里垃圾收集器的演进,得先明确一个核心判断:这绝不是那种每年刷个版本号、加点边角料的小修小补。相反,它是一次围绕低延迟、可预测性、大堆适配这三个关键词发起的实质性突破。最值得关注的不是多了个新收集器,而是G1和ZGC这两员大将,都藏了深度的战略级优化——结合最新的迭代思路来看,代际模型的回归与强化,才是这场升级的真正主线。
G1 的代际化重构:Generational G1
G1在JDK 21里最亮眼的动作是什么?答案是代际 G1(Generational G1)的正式引入。听起来像个术语调整,但背后的思路很关键。以前的G1虽然逻辑上也在分代,但Region的分配和回收策略并没有严格地把新生代和老年代拆清楚。从21开始,G1彻底改了——它开始显式维护年轻代Region和老年代Region的边界,并基于这个边界去优化行为。
具体来说,有三点值得单独拿出来讲讲:
- 年轻代回收现在做得更聚焦了,主要围着Eden和Survivor区域转,跨代扫描的开销压下来不少。
- 混合回收(Mixed GC)阶段里,老年代Region的选择也比以前聪明得多——优先清理那些垃圾多、引用关系简单的区域。
- 再加上改进后的并行全年轻代回收,Minor GC的停顿时间被进一步压缩。尤其是在高分配速率的场景下,稳定性提升非常明显。
简单说,以前是“大体上分代,但回收时还是有点模糊”,现在是“边界清晰,策略跟着代际走”。这个变化,对服务端应用来说,可以说是久等了。
ZGC 的亚毫秒级停顿落地
ZGC这边,JDK 21算是把当初的设计目标完全兑现了,甚至可以说超出了预期。几个硬指标摆出来,就很能说明问题:
- 最大停顿时间稳定控制在1 毫秒以内(sub-millisecond),而且这个指标跟堆大小(支持8MB到16TB)、存活对象的数量、根集规模统统无关。什么意思?就是说你堆越大,它越稳,而不是像老一代收集器那样堆越大越慌。
- 通过JEP 376(Concurrent Thread-Stack Processing),ZGC实现了线程栈的并发扫描。这直接拔掉了过去STW(Stop-The-World)里最不可控的一根刺。
- 着色指针(Colored Pointers)和内存重映射(Remap)全程并发,连对象移动都不需要暂停应用线程。这个设计在业界其实已经讨论很久,但真正做到生产级落地,ZGC是头一个。
这才是ZGC真正可怕的地方——它把“几乎不停顿”从口号变成了可测量的现实。
并发标记与混合回收的智能调度
进化的方向不光是“更快”,更在于“更懂什么时候该出手”。也就是说,策略本身变聪明了:
- G1的并发标记阶段,现在采用了更细粒度的锁和动态线程负载均衡。CPU热点被有效分散,多核利用率进一步拉高。
- 混合回收的触发机制里,引入了堆增长趋势预测模型。不再只盯着当前使用率的某个阈值做判断,少了误触发,也压住了延迟触发。
- Region回收的优先级计算,现在融合了垃圾密度、对象年龄、跨代引用强度等多个因子。回收效率更贴近真实业务压力的分布情况,而不是凭经验一刀切。
默认策略更务实:G1 仍是主力,ZGC 面向特定场景
还有一个很重要的结论值得单独拿出来说:JDK 21依然把G1列为默认GC,但同时对ZGC的生产就绪度做了彻底确认。这不是“G1稳压ZGC一头”,而是各有各的阵地。
- G1适合绝大多数服务端应用(4GB到64GB堆,延迟要求中等偏下的场景),覆盖面最广。
- ZGC不再是个“实验性选项”,而是被明确定位为延迟敏感型系统(比如高频交易、实时风控、游戏服务器)和超大堆场景(≥64GB)的首选方案。
- 至于CMS,已经在JDK 21里被彻底移除。Parallel GC也基本退守到吞吐量优先、且没有延迟约束的批处理任务中去了。
回头来看,整个演进路线其实很清晰:不是谁取代谁,而是让最适合的收集器在最合适的场景里跑出最好的性能。这才是生产环境真正需要的东西。
