终于把CMS垃圾收集器搞懂了~ (2)

此阶段也不停止应用程序,本阶段尝试在STW的最终标记阶段之前尽可能多做一些工作。本阶段的具体时间取决于多种因素,因为它循环做同样的事情,直到满足某个退出条件(如迭代次数、有用工作量、消耗的系统时间等等)
目标: 与并发预处理一样,为了使最终/重新标记的STW时间尽可能短
价值: 在进入最终标记前尽量等到一个Minor GC,尽量缩短最终标记阶段的停顿时间
触发条件: 在预清理步骤后,如果满足下面这个个条件,就会开启可中断的预清理,直接进入重新标记阶段

Eden的使用空间大于-XX:CMSScheduleRemarkEdenSizeThreshold”,这个参数的默认值是2M;

取消条件:

设置了CMSMaxAbortablePrecleanLoops循环次数,并且执行的次数大于或者等于这个值的时候。默认为0

CMSMaxAbortablePrecleanTime,执行可中断预清理的时间超过了这个值,这个参数的默认值是5000毫秒

Eden的使用率达到-XX:CMSScheduleRemarkEdenPenetration,这个参数的默认值是50%

问题: 可能在可取消的并发预处理过程中一直没等到Minor GC,这个时候进行最终标记的话,可能会发生连续停顿,假设新生代在最终标记的时候发生了Minor GC(STW),最终标记又是STW的,因此可能会发生连续停顿,CMS提供了参数CMSScavengeBeforeRemark使最终/重新标记前强制进行一次Minor GC(其实这样也会导致连续停顿,Minor和Remark)。

在这里插入图片描述

阶段5:最终标记/重标记

最终标记是此阶段GC事件中的第二次(也是最后一次)STW停顿。
目标: 重新扫描堆中的对象,因为之前的预清理阶段是并发执行的,有可能GC线程跟不上应用程序的修改速度。
扫描范围: 新生代对象+GC Roots+被标记为“脏”区的对象。如果预清理阶段没有做好,这一步扫描新生代的时候就会花很多时间。

阶段6:Concurrent Sweep(并发清除)

此阶段与应用程序并发执行,不需要STW停顿。JVM在此阶段删除不再使用的对象,并回收他们占用的内存空间。因为阶段5已经把所有还在使用的对象进行了标记,因此此阶段可以与应用线程并发的执行。

在这里插入图片描述

阶段7:Concurrent Reset(并发重置)

此阶段与应用程序并发执行,重置CMS算法相关的内部数据,为下一次GC循环做准备。


总之,CMS垃圾收集器在减少停顿时间上做了很多复杂的而有用的工作,用于垃圾回收的并行线程执行的同时,并不需要暂停应用线程。

动态检测机制

CMS会根据历史记录,预测老年代还有多长时间会满及进行一次回收所需的时间,可以使用参数_-XX:+UseCMSInitiatingOccupancyOnly_来关闭,开启这个参数后,配置的回收阈值-XX:CMSInitiatingOccupancyFraction=N会长期生效,否则只会第一次生效


缺点

吞吐量降低, 对处理器资源敏感,执行垃圾收集时会占用一部分线程时程序吞吐量降低

占用CPU资源,与CPU核数挂钩, 开头说到了CMS默认启动的回收线程是(CPU核心数 +3)/4,当CPU核数越多,垃圾回收线程占用的资源就越少,反正CPU核数越少,占用资源就越多。

内存碎片问题: 由于CMS使用的是标记-清除算法,这种算法的弊端就是会产生内存碎片,导致大对象无法分配,就会触发Full GC。

CMS收集器提供了一个参数-XX:+UseCMSCompactAtFullCollection(默认开启,JDK9废弃),在进行Full GC之前进行一次内存整理(无法并发,Shenandoah和ZGC可以),

这样空间碎片虽然解决了,但是停顿时间也增长了,CMS还提供了一个参数-XX:CMSFullGCBeforeCompaction=n(默认为0,表示每次进入Full GC时都进行碎片整理),参数作用是当CMS收集器执行过n次不整理内存碎片后,下一次进入Full GC前先进行碎片整理

无法处理“浮动垃圾”: 在并发收集阶段时,当用户线程创建了一个对象年轻代放不下,直接晋升到老年代或者年轻代对象晋升到老年代时老年代,由于存在这种情况,因此CMS垃圾收集器必须要预留一部分空间给用户线程(需要更大的堆空间),不能等到老年代满了才收集(JDK5及之前是68%,JDK6之后调整为92%,可通过 -XX:CMSInitiatingOccupancyFraction_=数值_+ -XX:+UseCMSInitiatingOccupancyOnly来设置)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwdzgx.html