为什么CMS收集器在初始标记阶段收集年轻代的根引用?

时间:2013-12-20 17:34:53

标签: java garbage-collection concurrent-mark-sweep

据我所知,CMS收集器收集老一代,它与ParNew收集器(用于收集年轻一代)一起工作。 我很难清楚地理解CMS是如何工作的,但这就是我看到它的方式:

1)初始标记。 寻找根参考。由于收集器是oldgen收集器,它应该只扫描老一代。

2)Concurrent-Mark 找到所有根引用后,就可以开始并发标记了。从第一阶段标记的对象可以传递的所有对象都标记在此阶段。

3)并发Preclean gc查看CMS堆中的对象,这些对象通过年轻代或新分配的促销更新,或者在我们在前一个并发标记阶段进行并发标记时由mutator更新。 [请确认那1这个阶段的唯一目的是做一些必须在下一阶段完成的工作(备注)? 2)有一些过程正在查看在并发标记阶段期间哪些参考被更改。 请告诉我这两项是否正确]

4)备注 gc停止世界,然后查看CMS堆中的对象,这些对象通过年轻代或新分配的促销更新,或者在我们进行并发预清洁时由mutator更新。

但今天我看到了这篇文章

  

初始标记在初始标记期间,CMS应收集所有根   参考开始标记旧空间。这包括:参考   来自线程堆栈,来自年轻空间的引用。参考文献来自   堆栈通常很快(小于1毫秒)收集,但时间到了   从年轻空间收集参考资料取决于对象的大小   年轻的空间。通常初始标记在年轻空间之后开始   集合,所以伊甸园空间是空的,只有活的物体在其中一个   幸存者空间。幸存者空间通常很小并且之后是初始标记   年轻的空间收集通常需要不到毫秒。但如果   当伊甸园已满时,初始标记开始可能需要很长时间   (通常比年轻的太空收藏本身更长)。一旦CMS   集合被触发,JVM可能会等待一段时间进行年轻收集   在它开始初始标记之前发生。 JVM配置   选项-XX:CMSWaitDuration =可用于设置CMS等待的时间   在初始标记开始之前用于年轻空间收集。如果你   想避免长时间的初始标记暂停,你应该配置它   时间长于你的年轻收藏品的典型时期   应用

     

备注大多数标记与应用程序并行完成,但它   可能不准确,因为应用程序可能会修改对象图   标记。并发标记完成后;垃圾收集器应该   停止应用程序并重复标记以确保所有可访问   标记为活着的对象。但收藏家不必遍历   通过整个对象图;它应该只遍历参考修改   自标记开始(实际上自开始预清洁阶段)。卡   table(参见卡片标记写屏障)用于标识修改   旧空间中的部分内存,但是线程堆栈和年轻空间   应再次扫描。 通常评论阶段的大部分时间是   花在扫描年轻空间。如果我们这个时间会短得多   在开始评论之前在年轻的空间收集垃圾。我们可以   指示JVM在CMS备注之前始终强制进行年轻空间收集。   使用JVM参数-XX:+ CMSScavengeBeforeRemark启用此选项。   即使年轻的空间是空的,评论阶段仍然需要扫描   在旧空间中修改了引用,这通常需要时间接近   正常的年轻收集暂停(由于扫描过去的旧空间)   年轻的收集类似于备注所需的扫描。

http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots_02.html

不明白为什么CMS需要扫描年轻一代。为什么旧代垃圾收集需要它?

2 个答案:

答案 0 :(得分:2)

你可能有包含循环引用的类,比如A类引用了B类,而B有A的反向引用。如果你有对象a和b属于这些类,并互相引用,gc从“外部”删除对它们的最后一个引用时必须删除它们。当然,包含更多元素的参考循环会使情况复杂得多。因此,gc必须检查哪些元素可以从某个根访问,哪些元素被引用但不可访问,应该被收集。

现在,如果你有代码中的某个地方

Object a=new A(new B(new C(new D())))

构造函数可能需要一些时间才能分配。但是你不希望gc删除新创建的D,只是因为C的构造函数需要一段时间才能运行,a尚未分配。因此,您还需要扫描年轻一代,以捕获太小而无法从堆中引用的对象。

答案 1 :(得分:2)

Java堆分为两部分,它们是独立收集的:旧空间和年轻空间。

要收集任何空间,您需要在空间外找到所有入站参考。他们是:

  • 堆栈中的局部变量
  • literal嵌入JIT编译代码blob
  • 来自其他空间的所有引用

旧的收藏应该扫描年轻的空间没有区别,年轻的收藏应该扫描旧的空间。

卡表写屏障用于不扫描每个年轻集合的整个旧空间(只有一小部分旧空间包含指向年轻人的链接,写屏障有助于跟踪这些区域)。

但是年轻空间没有卡表,所以旧的收藏应扫描整个内存范围。

PS我是您引用的文章的作者,您可以在my blog找到更多与GC相关的文章