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

标签 java garbage-collection concurrent-mark-sweep

据我所知,CMS收集器收集老一代,它与ParNew收集器(用于收集年轻代)结合使用。 对我来说,清楚地理解 CMS 的工作原理并不容易,但我是这样看的:

1) 初始标记。 寻找根引用。由于收集器是老一代收集器,因此它应该只扫描老一代。

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

3) 并发预清洁 gc 会查看 CMS 堆中的对象,这些对象是通过年轻代或新分配的提升而更新的,或者是在我们在上一个并发标记阶段进行并发标记时通过修改器更新的。 [请确认 1 此阶段的唯一目的是完成下一阶段必须完成的部分工作(备注)? 2)有一些进程正在查看哪些引用在并发标记阶段发生了更改。 请告诉我这两点是否正确]

4) 备注 gc 停止世界,然后查看 CMS 堆中的对象,这些对象是通过年轻代或新分配的提升而更新的,或者是在我们进行并发预清理时由修改器更新的。

但是今天我看到了这篇文章

Initial mark During initial mark CMS should collect all root references to start marking of old space. This includes: References from thread stacks, References from young space. References from stacks are usually collected very quickly (less than 1ms), but time to collect references from young space depends on size of objects in young space. Normally initial mark starts right after young space collection, so Eden space is empty and only live objects are in one of survivor space. Survivor space is usually small and initial mark after young space collection often takes less than millisecond. But if initial mark is started when Eden is full it may take quite long (usually longer than young space collection itself). Once CMS collection is triggered, JVM may wait some time for young collection to happen before it will start initial marking. JVM configuration option –XX:CMSWaitDuration= can be used to set how long CMS will wait for young space collection before start of initial marking. If you want to avoid long initial marking pauses, you should configure this time to be longer than typical period of young collections in your application.

Remark Most of marking is done in parallel with application, but it may not be accurate because application may modify object graph during marking. When concurrent marking is finished; garbage collector should stop application and repeat marking to be sure that all reachable objects marked as alive. But collector doesn’t have to traverse through whole object graph; it should traverse only reference modified since start of marking (actually since start pre clean phase). Card table (see card marking write barrier) is used to identify modified portions of memory in old space, but thread stacks and young space should be scanned once again. Usually most time of remark phase is spent of scanning young space. This time will be much shorter if we collect garbage in young space before starting of remark. We can instruct JVM to always force young space collection before CMS remark. Use JVM parameter –XX:+CMSScavengeBeforeRemark to enable this option. Even is young space is empty, remark phase still have to scan through modified references in old space, this usually takes time close to normal young collection pause (due scanning of old space done during young collection is similar to scanning required for remark).

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

不明白为什么CMS需要扫描年轻代。为什么需要老年代垃圾回收?

最佳答案

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

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

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

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

关于java - 为什么CMS收集器在初始标记阶段收集年轻代的根引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20709033/

相关文章:

java - SDK 最小或最佳页面安装

java - 我想使用 NCDC(国家气候数据中心)气候数据 API 根据邮政编码获取美国过去的最高和最低气温

用于生成 C++ 源代码的 Java 库

java - 使用 .clear() 或让 GC 处理它

java - Spring Boot Controller 应如何处理 'missing' 请求 header ?

具有极值实时值的 Java GC 日志

java - G1 和 CMS 的 UseCompressedOops 启动阈值不同

java - "final remark"中CMS的具体工作是什么?

java - 可以增加引用旧对象的 gc 时间短命对象吗?

java - 从本地方法返回由 JNI 创建的本地引用