面试题:Java 的 CMS 垃圾回收器和 G1 垃圾回收器在记忆集的维护上有什么不同?

在 Java 中,CMS(Concurrent Mark-Sweep)和 G1(Garbage-First)是两种常见的垃圾回收器,它们在记忆集(Remembered Set,简称 RSet)的维护上有一些显著的不同。记忆集的主要作用是记录跨代引用(例如老年代对象引用新生代对象),以便在垃圾回收时快速定位这些引用,避免全堆扫描。

以下是 CMS 和 G1 在记忆集维护上的主要区别:


1. CMS 的记忆集维护

CMS 是一种基于分代的垃圾回收器,主要针对老年代的并发标记清除。它的记忆集维护相对简单:

  • 卡表(Card Table):CMS 使用卡表来维护记忆集。卡表是一个字节数组,每个字节对应老年代中的一小块内存区域(称为“卡片”)。当老年代中的对象引用新生代对象时,对应的卡片会被标记为“脏”。
  • 写屏障(Write Barrier):CMS 通过写屏障机制来更新卡表。当老年代对象引用新生代对象时,写屏障会标记对应的卡片为脏。
  • 扫描范围:在 Minor GC 时,CMS 只需要扫描卡表中标记为脏的卡片,而不需要扫描整个老年代。

特点

  • CMS 的记忆集维护较为简单,主要依赖卡表和写屏障。
  • 卡表的粒度较粗(通常为 512 字节或更大),可能会导致一些不必要的扫描。
  • CMS 的记忆集主要用于新生代垃圾回收(Minor GC),而不用于老年代垃圾回收。

2. G1 的记忆集维护

G1 是一种面向全堆的垃圾回收器,它将堆划分为多个大小相等的区域(Region),每个区域可以是 Eden、Survivor 或 Old 区。G1 的记忆集维护更加精细:

  • 精细化的记忆集:G1 为每个区域维护一个记忆集,记录其他区域对该区域的引用。每个记忆集是一个哈希表,存储了指向该区域的引用来源。
  • 写屏障:G1 的写屏障机制更加复杂。当一个对象引用另一个对象时,写屏障会检查引用是否跨区域。如果是跨区域引用,则更新目标区域的记忆集。
  • 扫描范围:在垃圾回收时,G1 只需要扫描相关区域的记忆集,而不需要扫描整个堆。

特点

  • G1 的记忆集维护更加精细,每个区域都有自己的记忆集。
  • 记忆集的粒度更细(基于对象引用),减少了不必要的扫描。
  • G1 的记忆集不仅用于新生代垃圾回收,还用于老年代垃圾回收(Mixed GC 和 Full GC)。

3. CMS 和 G1 记忆集维护的对比

特性CMSG1
记忆集结构卡表(Card Table)每个区域的哈希表(精细记忆集)
粒度较粗(卡片级别,通常 512 字节)较细(对象引用级别)
写屏障复杂度简单复杂
适用范围主要用于 Minor GC用于 Minor GC 和 Mixed GC
内存开销较低较高(每个区域维护一个记忆集)
扫描效率可能存在不必要的扫描更精确,减少不必要的扫描

4. 总结

  • CMS 的记忆集维护基于卡表,实现简单,但粒度较粗,可能会导致一些不必要的扫描。它主要用于新生代垃圾回收。
  • G1 的记忆集维护更加精细,每个区域都有自己的记忆集,减少了不必要的扫描,但内存开销和写屏障的复杂度更高。G1 的记忆集不仅用于新生代垃圾回收,还用于老年代垃圾回收。

选择 CMS 还是 G1 取决于具体的应用场景。如果应用对停顿时间敏感且堆内存较大,G1 可能是更好的选择;如果应用对吞吐量要求较高且堆内存较小,CMS 可能更适合。

THE END
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容