CMS(Concurrent Mark-Sweep)和 G1(Garbage First)垃圾收集器在Java中通过不同的机制来维持并发操作的正确性,即确保在应用程序线程与垃圾收集器线程同时运行时不会导致数据不一致或错误。
下面分别介绍这两种收集器如何实现这一点:
CMS 垃圾收集器
CMS主要通过以下几种方式保证并发操作的正确性:
- 写屏障(Write Barrier):为了处理并发标记阶段中新创建的对象以及对象间引用的变化,CMS使用了写屏障技术。当应用程序修改对象引用时,写屏障会记录这些更改,以便垃圾收集器可以在后续阶段重新检查这些变化。
- 初始标记(Initial Mark)和再标记(Remark)阶段:
- 初始标记是一个短暂的“Stop the World”阶段,在此期间,CMS会标记直接从GC根可达的对象。
- 再标记阶段也是另一个短暂的暂停,目的是完成标记工作,处理在并发标记阶段内由于程序活动而改变了的对象引用。
- 并发清除(Concurrent Sweep):虽然这个阶段是并发执行的,但由于它只是简单地释放不再使用的对象所占用的空间,并不需要移动存活对象的位置,因此不会引起一致性问题。
G1 垃圾收集器
G1同样依赖于写屏障技术来维护并发操作的正确性,但其具体实现略有不同,因为它还需要处理对象的移动以减少内存碎片化的问题:
- 写屏障(Card Table & Remembered Set):G1使用了一种称为“卡片表”(Card Table)的技术来跟踪跨区域的引用。每个区域被划分为多个小块(卡片),每当一个区域内的对象引用发生变化时,相应的卡片会被标记为脏(dirty)。
此外,G1还维护了一个“记住集”(Remembered Set),用于记录其他区域指向本区域的引用。这使得G1能够在不扫描整个堆的情况下识别出哪些区域包含了指向特定区域的引用。 - 并发标记(Concurrent Marking):类似于CMS,G1也包括初始标记、并发标记、最终标记等阶段。在此过程中,G1利用写屏障记录所有可能影响标记结果的变更,从而确保即使在应用线程继续运行的同时也能准确地标记存活对象。
- 并发清理与压缩(Concurrent Cleanup and Compaction):不同于CMS,G1不仅能够并发地清理死亡对象,还可以在某些情况下并发地对存活对象进行压缩,避免内存碎片化。
这一过程需要特别小心地管理对象的移动及其引用更新,确保在对象移动后所有的引用都能正确指向新的位置。
总结来说,无论是CMS还是G1,它们都依靠写屏障技术来监测并记录对象引用的变化,以此来保证在并发执行垃圾回收的过程中不会丢失任何重要的信息,确保垃圾回收的正确性和高效性。
对于G1而言,除了基本的写屏障外,还增加了复杂的机制如卡片表和记住集,以便更好地支持区域化的堆管理和对象压缩。
THE END