据我所知,CMS 收集器收集老年代,它与 ParNew 收集器(用于收集年轻代)一起工作。对我来说,要清楚地理解 CMS 的工作原理并不容易,但这是我的看法:
1) 初始标记。寻找根参考。由于收集器是 oldgen 收集器,它应该只扫描老年代。
2) Concurrent-Mark 找到所有根引用后,就该开始并发标记了。从第一阶段标记的对象可传递到达的所有对象都在该阶段标记。
3) 并发预清理 gc 查看 CMS 堆中的对象,这些对象在我们在前一个并发标记阶段进行并发标记时由年轻代的提升或新分配更新或由突变器更新。[请确认1 这个阶段的唯一目的是完成下一个阶段必须完成的部分工作(备注)?2) 有一些进程正在查看在并发标记阶段更改了哪些引用。请告诉我我对这两个项目是否正确]
4) 备注 gc 停止世界,然后查看 CMS 堆中的对象,这些对象在我们进行并发预清理时由年轻代的提升或新分配更新或由 mutators 更新。
但是今天看到这篇文章
初始标记在初始标记期间,CMS 应收集所有根引用以开始标记旧空间。这包括:来自线程堆栈的引用、来自年轻空间的引用。来自堆栈的引用通常被收集得非常快(小于 1ms),但是从年轻空间收集引用的时间取决于年轻空间中对象的大小。通常初始标记在年轻空间收集后立即开始,因此伊甸园空间是空的,只有存活对象位于幸存者空间之一。幸存者空间通常很小,年轻空间收集后的初始标记通常需要不到毫秒的时间。但是,如果在 Eden 已满时开始初始标记,则可能需要很长时间(通常比年轻空间收集本身更长)。一旦触发了 CMS 收集,JVM 可能会等待一段时间让年轻收集发生,然后才会开始初始标记。JVM 配置选项 –XX:CMSWaitDuration= 可用于设置 CMS 在开始初始标记之前等待年轻空间收集的时间。如果您想避免长时间的初始标记暂停,您应该将此时间配置为比应用程序中年轻集合的典型周期更长。
备注大部分标记与应用程序并行完成,但可能不准确,因为应用程序可能会在标记期间修改对象图。并发标记完成时;垃圾收集器应该停止应用程序并重复标记,以确保所有可到达的对象都标记为活动的。但是收集器不必遍历整个对象图;它应该只遍历自标记开始以来修改的参考(实际上是自开始预清洁阶段以来)。卡片表(参见卡片标记写屏障)用于识别旧空间中内存的修改部分,但应再次扫描线程堆栈和年轻空间。 通常remark阶段的大部分时间都花在扫描年轻空间上。如果我们在评论开始之前在年轻空间中收集垃圾,这个时间会短得多。我们可以指示 JVM 在 CMS 备注之前始终强制进行年轻空间收集。使用 JVM 参数 –XX:+CMSScavengeBeforeRemark 启用此选项。即使年轻空间是空的,remark 阶段仍然需要扫描 old space 中的修改引用,这通常需要接近正常年轻收集暂停的时间(由于在年轻收集期间完成的 old space 扫描类似于 remark 所需的扫描)。
http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots_02.html
不明白为什么 CMS 需要扫描年轻代。为什么老年代垃圾回收需要它?