别再背八股了!面试说清 CMS 回收器,就靠这篇了

“面试官问我 CMS 是什么,我脑子一热,差点说成了‘内容管理系统’!”这是我一个做了5年 Java 的朋友最近社招面试的真实经历。从这件事我意识到,CMS(Concurrent Mark Sweep)垃圾回收器,虽然老牌,但在很多面试中依然是重点。所以今天,小米就来讲讲我是怎么“跟 CMS 打交道”的——希望能帮到即将跳槽、社招面试的你。

故事的起点:我和 CMS 的第一次“相遇”

还记得那年我第一次维护一个线上老项目,Tomcat 启动参数里赫然写着:

-XX:+UseConcMarkSweepGC

当时的我一脸懵:“这啥?新玩意儿?”

我去查资料才知道,原来它就是传说中的“低延迟垃圾回收器”——CMS,老年代的明星选手,曾一度是互联网公司争相使用的主流 GC 方案。

而这次,也让我开始正式接触 JVM 内存管理的世界。

CMS 的目标是什么?

CMS,全称是 Concurrent Mark Sweep,中文叫“并发标记-清除”。顾名思义,它的最大特点就是——尽量减少 STW(Stop The World)时间,也就是让垃圾回收这件事尽量不打扰业务线程运行

它的“信仰”是:用户体验优先,延迟比吞吐更重要。

也正因为如此,它被广泛用于对响应时间有要求的 Web 服务类系统,像电商、支付、在线教育等系统中。

CMS 的工作流程(记住这四个阶段)

在我看来,CMS 就像是个不打扰别人的清洁工,它一边让用户用着房间,一边偷偷打扫:

1、初始标记(Initial Mark)

  • 短暂停顿(STW)
  • 标记所有 GC Root 直接关联的对象
  • 非常快,一般几毫秒内完成

2、并发标记(Concurrent Mark)

  • 和应用线程同时进行
  • 遍历整个对象图,找出存活对象

3、重新标记(Remark)

  • 再次暂停(STW)
  • 解决并发标记期间产生的对象变动(比如新引用)
  • 相对耗时,是整个过程的瓶颈之一

4、并发清除(Concurrent Sweep)

  • 清理垃圾对象,回收空间
  • 同样是和用户线程一起进行的

总结一句话:只有初始标记和重新标记两个步骤会暂停应用,其它阶段是“边跑边收”。

我踩过的几个 CMS“大坑”

作为一个在生产环境中维护过 CMS 回收器的人,小米必须给你讲几个“实战坑点”。

  1. 碎片化严重

CMS 是“标记-清除”算法,所以不会像 G1 或 Parallel Old 那样做“压缩”。清理之后留下的是“一个个小碎片”。

这意味着:大对象分配容易失败,即使总内存够,但没有一块连续空间就 GG。

解决方案:加上 -XX:+UseCMSCompactAtFullCollection 参数(默认就是 true),并设定压缩频率 -XX:CMSFullGCsBeforeCompaction=5,让 CMS 每执行几次 Full GC 就顺带整理一次空间。

  1. 并发失败(Concurrent Mode Failure)

这个问题听上去就让人心慌:回收器还没干完活,堆就满了!

这通常发生在 CMS 清理速度赶不上对象增长速度时,JVM 被迫切换为“Stop The World 的 Serial Old”模式,系统就顿了,甚至会出现卡顿报警。

应对方法:

  • 增加老年代大小 -XX:CMSInitiatingOccupancyFraction=75(默认是92)
  • 启用 -XX:+UseCMSInitiatingOccupancyOnly 控制 GC 触发时机
  1. 浮动垃圾(Floating Garbage)

由于 CMS 在并发标记、清理期间,业务线程还在创建新对象,所以这些“新生代对象”在 GC 时根本就没看见。

这些没清理到的对象就叫:浮动垃圾

这就是为什么 CMS 没法做到“完全回收”,它需要依靠多次回收才能慢慢清理干净。

看新机会的可看看

民族企业核心部门,前、后端or测试>>>机会 待遇还可以,感兴趣试试~

再聊聊 CMS 的参数优化

你面试的时候,光说机制还不够,能讲讲调优,就显得你“干过活”。

常见调优参数:

经验值建议:

  • 新生代大小设大一点,避免频繁 Minor GC
  • 老年代使用率到 70~75% 左右就开始 GC
  • 定期触发 Full GC,压碎片(适度使用)

CMS 的退场:被谁取代了?

2017 年 Oracle 宣布:CMS 将在 JDK 9 后被标记为“deprecated”

它的接班人是谁?那就是 G1(Garbage First)

为什么?因为:

  • G1 支持压缩(解决了碎片问题)
  • G1 更智能(自动按 Region 分区)
  • G1 有更短更可控的暂停时间

不过,如果你面试中提到:“虽然 CMS 被 G1 替代,但它依然在很多线上系统中运行,了解它是必要的。”——你绝对是加分项!

面试怎么说 CMS?

来,小米总结一段“答题模板”送你:

CMS 是一种以降低 GC 停顿时间为目标的垃圾回收器,采用标记-清除算法,在初始标记和重新标记阶段会暂停业务线程,其余阶段与业务线程并发执行。适用于对响应时间要求高的场景。缺点是内存碎片化严重、容易出现并发失败。调优时可以设置 CMSInitiatingOccupancyFraction 来提前触发 GC,并定期做 Full GC 以压缩空间。目前 CMS 在 JDK 9 后已被标记为废弃,G1 是其继任者。

简洁、有层次、还带优化经验,一听就是干过的!

建议

如果你还在用 CMS,那一定要:

  • 监控老年代使用率
  • 留意 GC 日志是否出现 Concurrent Mode Failure
  • 考虑是否能升级 G1 或 ZGC(JDK11+)

而如果你准备社招,别光死背概念,要结合故事、项目、场景去说,才能让面试官感受到你的“实战经验”。

END

CMS 是一段经典的 JVM 回忆,也是 Java 调优道路上的“必经之坑”。虽然它已经慢慢退场,但它的机制和思维,依然影响着后来的垃圾回收器设计。

面试,是回顾和总结的好机会。希望今天的这篇文章,能帮你更自信地面对面试中的 JVM 回收问题,也希望你不再被 CMS 的“初始标记”和“重新标记”绕晕啦。

如果你觉得这篇文章有帮助,欢迎点赞、转发给正在找工作的朋友,也欢迎留言说说你被 CMS“坑”过的经历,我们一起成长!

——转载自:软件求生

全部评论

相关推荐

08-06 16:14
重庆工程学院
1. 自我介绍2. 项目和实习3. 订单流转详细介绍4. 那假如,比如说消息量比较大的情况下,在这里如何去保证它能比较快速的感知到,就让用户能够减少他的等待时间来感知到这订单是完成,或者说是是失败呢?5. 并发场景下,就是你对线程之间状态的一些流转。6. 讲一讲你对 CAS 的理解7. ABA 问题8. synchronized 和 ReentrantLock 的一些区别。9. 他那个 ReentrantLock, 你刚才提到有实现公平锁,或者说是一些其他的,那他如何去实现他的可重入呢?10. 讲一下 CompletableFuture11. JVM 内存区域12. Java 对象,它一定是在堆上分配内存吗?13. 完整的 GC 流程14. 就是空间不足嘛。那除了这个空间不足,还有一些其他条件可以触发 Full GC 吗15. 空间分配担保16. G1, CMS, 它们的一些区别,或者说是特点分别是什么17. 你认为多久一次 GC, Full GC 算是正常的18. 新生代和老年代之间的跨代引用19. Redis 的集群部署20. Redis 就是比如说它经常用于我们一些缓存,或者一些比较常见的场景,那为什么要使它来?或者说它为什么会这么快的一些原因21. Redis 的单线程模型22. Redis 的 set 底层23. Set 扩容前后的变化24. 跳表25. Redis 的事务机制,对 Redis 的事务机制有什么了解?26. Redis 的持久化27. 什么情况下会采用 RDB,什么情况下采用 AOF 呢?28. Redis 的热 key 和大 key29. Redis 缓存和真正 MySQL 这个数据库里数据不一致,这种情况是怎么去解决和维护的?30. Redis 实现的分布式锁31. Redission32. 聚簇索引33. 回表34. 索引覆盖和索引下推35. InnoDB 的引擎下的一次事务更新的过程是怎样的36. 继续讲一下这个事务的二阶段提交是,的流程以及作用。37. Spring 的循环依赖38. Es 的倒排索引
点赞 评论 收藏
分享
评论
4
9
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务