理解CMS回收器的preclean阶段

CMS垃圾收集器在《深入理解Java虚拟机》中描述的四个阶段外,还包括concurrent-preclean和concurrent-abortable-preclean。concurrent-preclean用于清理card marking的脏卡,更新引用信息;concurrent-abortable-preclean则尝试减少final-remark阶段的暂停时间,通过迭代清理脏卡并调整其开始时机,以避免连续STW。这两个阶段涉及了跨代引用、Card Marking和写屏障等概念,通过配置参数如CMSScheduleRemarkEdenPenetration、CMSScheduleRemarkEdenSizeThreshold和CMSMaxAbortablePrecleanTime来控制其行为。

在《深入理解 Java 虚拟机:JVM 高级特性与最佳实践(第二版)》里这样介绍 CMS 回收器的工作过程:

CMS 收集器是基于“标记—清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为 4 个步骤,包括: •初始标记(CMS initial mark) •并发标记(CMS concurrent mark) •重新标记(CMS remark) •并发清除(CMS concurrent sweep)

很多人可能只看了这本书的介绍(实际这应该只是作者的概括),就认为 CMS 回收器就只有这 4 个阶段,看一下这里的 gc log:

0.245: [GC (CMS Initial Mark) [1 CMS-initial-mark: 32776K(53248K)] 41701K(99328K), 0.0061676 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
0.251: [CMS-concurrent-mark-start]
0.270: [CMS-concurrent-mark: 0.004/0.020 secs] [Times: user=0.08 sys=0.01, real=0.02 secs]
0.270: [CMS-concurrent-preclean-start]
0.272: [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.272: [CMS-concurrent-abortable-preclean-start]
0.291: [CMS-concurrent-abortable-preclean: 0.004/0.019 secs] [Times: user=0.09 sys=0.00, real=0.02 secs]
0.291: [GC (CMS Final Remark) [YG occupancy: 17928 K (46080 K)]0.291: [Rescan (parallel) , 0.0082702 secs]0.299: [weak refs processing, 0.0000475 secs]0.299: [class unloading, 0.0002451 secs]0.299: [scrub symbol table, 0.0003183 secs]0.300: [scrub string table, 0.0001611 secs][1 CMS-remark: 49164K(53248K)] 67093K(99328K), 0.0091462 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
0.300: [CMS-concurrent-sweep-start]
0.300: [CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.300: [CMS-concurrent-reset-start]
JVMCMS(Concurrent Mark Sweep)垃圾回收器是一种以低停顿为目标的垃圾收集器,广泛应用于对响应时间有较高要求的应用场景中。CMS的垃圾回收过程分为多个阶段,其中`preclean`阶段是标记阶段的一部分,主要用于并发标记期间对象引用的变化进行修正,以减少后续`remark`阶段的工作量。 在CMS的`preclean`阶段中,如果由于时间限制导致该阶段被中止,通常意味着CMS无法在指定的时间内完成该阶段的任务。这种情况可能会导致以下后果: 1. **增加remark阶段的负担**:由于`preclean`阶段未能完成,未处理的对象变化需要在后续的`remark`阶段中进行处理,这将增加`remark`阶段的停顿时间,从而抵消CMS低停顿的优势[^1]。 2. **影响整体性能**:频繁的`preclean`阶段中止可能导致CMS频繁触发Full GC,进而影响应用的整体性能和稳定性。 ### 解决方案 为了解解决CMS在`preclean`阶段因时间原因中止的问题,可以采取以下措施: 1. **调整CMS参数**: - **`CMSMaxAbortablePrecleanLoops`**:该参数控制`preclean`阶段中止前的最大循环次数。增加该值可以让CMS在`preclean`阶段有更多机会完成任务。 - **`CMSScheduleRemarkEdenSizeThreshold`**:该参数用于控制`remark`阶段的触发时机。适当调整该值可以优化`preclean`和`remark`阶段之间的平衡。 - **`CMSScavengeBeforeRemark`**:启用该参数可以在`remark`阶段之前进行一次Young GC,从而减少`remark`阶段需要处理的对象数量。 2. **优化堆内存配置**: - 增加堆内存大小可以减少垃圾回收的频率,从而为`preclean`阶段提供更多的时间。 - 调整新生代和老年代的比例,确保老年代有足够的空间容纳长期存活的对象。 3. **减少对象分配速率**: - 通过优化代码减少不必要的对象创建,降低垃圾回收的压力。 - 使用对象池或复用机制,减少短期对象的生成。 4. **监控与调优**: - 使用JVM自带的监控工具(如`jstat`、`jvisualvm`等)分析垃圾回收的日志,识别`preclean`阶段中止的具体原因。 - 根据监控结果调整CMS的相关参数,优化垃圾回收性能。 ### 示例代码 以下是一个简单的JVM参数配置示例,用于优化CMS的`preclean`阶段: ```bash java -XX:+UseConcMarkSweepGC \ -XX:CMSMaxAbortablePrecleanLoops=10 \ -XX:CMSScheduleRemarkEdenSizeThreshold=2M \ -XX:+CMSScavengeBeforeRemark \ -Xms4g -Xmx4g \ -jar your_application.jar ``` 在上述配置中: - `-XX:+UseConcMarkSweepGC`启用CMS垃圾回收器。 - `-XX:CMSMaxAbortablePrecleanLoops=10`设置`preclean`阶段的最大循环次数为10。 - `-XX:CMSScheduleRemarkEdenSizeThreshold=2M`设置`remark`阶段的触发阈值为2MB。 - `-XX:+CMSScavengeBeforeRemark`启用`remark`阶段之前的Young GC。 ### 总结 CMS垃圾回收器的`preclean`阶段中止问题通常是由于时间限制导致的。通过调整CMS的相关参数、优化堆内存配置、减少对象分配速率以及进行监控与调优,可以有效缓解这一问题。确保`preclean`阶段顺利完成,有助于减少`remark`阶段的停顿时间,从而提升应用的整体性能和稳定性[^1]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值