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