在Java中,CMS(Concurrent Mark Sweep)和G1(Garbage-First)是两种常见的垃圾收集器,它们各自采用了一系列机制来维持并发过程中的正确性。以下是对这两种垃圾收集器如何维持并发正确性的详细解释:
CMS垃圾收集器
CMS(Concurrent Mark Sweep)垃圾收集器旨在最小化垃圾收集过程中的停顿时间,通过并发执行垃圾收集的大部分工作来实现。它主要通过以下几个步骤来维持并发的正确性:
- 初始标记(Initial Mark):
- 这是一个“Stop-The-World”事件,即暂停所有应用线程,仅标记GC Roots能直接关联到的对象。此阶段时间较短,以减少对应用的影响。
- 并发标记(Concurrent Mark):
- 在此阶段,GC线程与应用线程并发执行。GC线程从GC Roots开始,遍历整个对象图,标记所有可达对象。这一步骤是并发的,不会暂停应用线程。
- 重新标记(Remark):
- 由于并发标记阶段应用线程仍在运行,可能会产生新的垃圾对象,因此需要进行一次短暂的“Stop-The-World”来修正这些新增对象的标记,并处理并发阶段的浮动垃圾。
- 并发清理(Concurrent Sweep):
- 在这一阶段,GC线程与应用线程并发执行,清理在重新标记阶段被标记为可回收的对象。
维持并发正确性的关键:
- 并发标记与清理:CMS通过允许GC线程与应用线程并发执行,显著减少了垃圾收集过程中的停顿时间。
- 原始快照(虽然CMS本身不直接提及“原始快照”,但类似的概念在并发环境中用于解决对象引用的变化问题):CMS通过记录对象引用在并发阶段的变化,确保能够准确标记所有存活对象。
- 重新标记阶段:修正并发标记阶段可能遗漏的对象,确保垃圾收集的准确性。
G1垃圾收集器
G1垃圾收集器旨在提供可预测的停顿时间,同时保持高吞吐量。它通过以下机制来维持并发的正确性:
- 区域划分(Region Division):
- G1将堆内存划分为多个大小相等的独立区域(Region),这些区域可以是Eden区、Survivor区或老年代区。
- 并发标记(Concurrent Marking):
- G1使用并发标记来识别存活对象。这一过程与应用线程并发执行,减少了停顿时间。
- 原始快照(Original Snapshot):
- G1采用原始快照技术来解决并发标记过程中对象引用的变化问题。这有助于确保在并发环境中准确标记存活对象。
- 筛选回收(Evacuation Pause):
- 根据用户期望的停顿时间,G1会优先回收价值最高的区域(即垃圾最多的区域)。在回收过程中,会暂停应用线程,将存活对象复制到其他区域,并回收原区域的空间。
维持并发正确性的关键:
- 区域划分:通过区域划分,G1可以独立地管理堆内存的不同部分,减少跨区域的引用问题。
- 并发标记与筛选回收:G1通过并发标记和基于优先级的筛选回收来减少停顿时间,同时确保垃圾收集的准确性。
- 原始快照:用于解决并发标记过程中对象引用的变化问题,确保标记过程的正确性。
综上所述,CMS和G1垃圾收集器通过并发标记、重新标记(CMS特有)、筛选回收(G1特有)以及原始快照等机制,有效地维持了并发过程中的正确性,同时减少了垃圾收集对应用性能的影响。