3 分钟吃透 JVM 垃圾回收器!不同场景怎么选,这篇说透不踩坑

B站影视 韩国电影 2025-09-26 11:20 1

摘要:作为 Java 开发,你是不是也有过这种困惑:项目刚上线时性能好好的,跑着跑着就频繁 GC 卡顿?排查半天发现,竟然是垃圾回收器选得不对!别慌,今天这篇干货直接帮你理清 JVM 里那些常见的垃圾回收器,每种适合啥场景、避坑点在哪,一次性说明白。

作为 Java 开发,你是不是也有过这种困惑:项目刚上线时性能好好的,跑着跑着就频繁 GC 卡顿?排查半天发现,竟然是垃圾回收器选得不对!别慌,今天这篇干货直接帮你理清 JVM 里那些常见的垃圾回收器,每种适合啥场景、避坑点在哪,一次性说明白。

在聊具体的回收器之前,得先明确一个核心:JVM 垃圾回收器没有 “万能款”,不同的回收器设计目标天差地别。有的追求 “吞吐量优先”,适合后台批处理任务;有的主打 “低延迟”,专门应对电商秒杀这类高并发场景;还有的兼顾内存规模,能扛住大堆内存压力。

要是把主打吞吐量的回收器用在要求毫秒级响应的接口服务里,大概率会出现几秒的 GC 停顿,用户直接被卡走;反过来,用低延迟回收器跑大数据批处理,资源开销蹭蹭涨,服务器扛不住不说,任务还跑得慢。所以选对回收器,相当于给项目性能上了道 “保险”。

1. 基础款回收器:Serial & Serial Old,小内存项目的 “性价比之选”

核心特点

这对 “老搭档” 是最基础的串行回收器,采用单线程执行垃圾回收,回收时会暂停所有用户线程(也就是常说的 “Stop The World”,STW)。Serial 负责新生代回收,用复制算法;Serial Old 负责老年代回收,用标记 - 整理算法。

适用场景

内存规模小的场景:堆内存小于 2GB 的桌面应用、工具类程序,比如本地运行的 Java Swing 程序。

单核 CPU 环境:单线程回收不会产生线程切换开销,反而比多线程回收效率更高。

避坑点

绝对别用在服务器端应用!哪怕是小型接口服务,只要并发量稍微上来,STW 时间能达到几百毫秒,用户体验直接崩。

2. 吞吐量王者:Parallel Scavenge & Parallel Old,后台任务的 “得力干将”

核心特点

这组是并行回收器,新生代和老年代都采用多线程回收,设计目标就是 “高吞吐量”(吞吐量 = 用户线程运行时间 /(用户线程运行时间 + GC 时间))。可以通过参数调整吞吐量目标,比如设置 “-XX:GCTimeRatio=19”,表示 GC 时间占比不超过 5%。

适用场景

后台批处理任务:比如大数据 ETL、日志分析、报表生成等,这类任务不要求实时响应,更看重单位时间内处理的数据量。

资源受限的服务器:比如多核心但内存不算超大的应用服务器,并行回收能充分利用 CPU 资源。

实战案例

之前帮朋友优化过一个日志分析系统,原本用 Serial 回收器,处理 100GB 日志要 2 小时,换成 Parallel 组合后,吞吐量提升了 30%,1.5 小时就搞定了,而且服务器 CPU 利用率从 40% 涨到了 70%,资源利用更充分。

3. 低延迟代表:CMS,高并发服务的 “老伙计”

核心特点

CMS(Concurrent Mark Sweep)是老年代回收器,主打 “低延迟”,通过 “初始标记 - 并发标记 - 重新标记 - 并发清除” 四个阶段实现,除了初始标记和重新标记阶段有短暂 STW,其余阶段都能和用户线程并行。

适用场景

高并发实时服务:电商详情页、支付接口、即时通讯等,要求响应时间控制在 100 毫秒以内的场景。

用户体验敏感型应用:比如在线教育的直播互动功能,卡顿一秒都可能影响用户留存。

避坑点

内存碎片问题:CMS 用标记 - 清除算法,长期运行会产生大量内存碎片,可能导致明明有空闲内存却无法分配,触发 Full GC。可以通过 “-XX:+UseCMSCompactAtFullCollection” 参数在 Full GC 后进行内存整理。

CPU 消耗高:并发回收需要额外的线程参与,会占用 10%-20% 的 CPU 资源,单核服务器慎用。

4. 全能选手:G1,大内存场景的 “首选方案”

核心特点

G1(Garbage-First)是 JDK 9 之后的默认回收器,打破了新生代和老年代的物理划分,把堆内存分成多个大小相等的 Region。它能同时兼顾吞吐量和延迟,还支持可预测的停顿时间(通过 “-XX:MaxGCPauseMillis” 设置目标停顿时间)。

适用场景

大堆内存应用:堆内存超过 8GB 的服务,比如分布式微服务网关、大型电商后台,G1 的 Region 设计能避免全堆扫描,大幅缩短 STW 时间。

混合场景需求:既要求一定吞吐量,又不能有过长停顿的应用,比如短视频的推荐接口,既要处理大量请求,又要保证用户刷视频不卡顿。

优势体现

之前公司的订单系统从 CMS 迁移到 G1,堆内存 16GB,原本 CMS 偶尔会出现 200 毫秒的 STW,换成 G1 后,设置最大停顿时间 50 毫秒,实际运行中基本稳定在 30-40 毫秒,订单处理峰值提升了 15%。

5. 新一代黑马:ZGC & Shenandoah,超大内存的 “性能天花板”

核心特点

这两款是 JDK 11 之后推出的低延迟回收器,主打 “亚毫秒级 STW”,即使堆内存达到 TB 级,STW 时间也能控制在 10 毫秒以内。它们采用了更先进的并发处理技术,比如 ZGC 的着色指针、Shenandoah 的连接矩阵。

适用场景

超大内存场景:堆内存 32GB 以上的大型系统,比如金融行业的核心交易系统、云计算中的容器服务。

极致低延迟需求:高频交易、实时数据分析等,响应时间要求达到毫秒级甚至亚毫秒级的场景。

注意事项

目前部分老版本中间件对这两款回收器支持不够完善,迁移前一定要做充分的兼容性测试。另外,它们对 CPU 的要求较高,建议在 8 核以上的服务器上使用。

别盲目跟风用 “新回收器”:ZGC 虽好,但如果你的项目堆内存才 4GB,用 G1 反而更省资源,新技术不一定适配你的场景。

参数不是越调越优:很多人喜欢堆一堆 GC 参数,其实默认参数已经能满足大部分场景,过度调优反而容易出问题。

一定要结合监控:选好回收器后,用 JVisualVM、Grafana 等工具监控 GC 频率和停顿时间,根据实际运行情况调整。

看完这篇,你是不是对回收器选型心里有底了?赶紧去查查自己项目用的是哪种回收器,有没有踩错场景!欢迎在评论区分享你的项目场景和回收器选择,遇到过哪些 GC 坑,咱们一起交流避坑经验~觉得有用的话,别忘了收藏转发,下次选型直接拿出来对照!

来源:从程序员到架构师

相关推荐