承上启下,JDK9标记作废,JDK14删除
- 初始标记和重新标记阶段仍然需要STW机
- 由于在垃圾收集阶段用户线程没有中断,所以在CMS回收过程中,还应该确保应用程序用户线程有足够的内存可用。因此CMS收集器不能像其他收集器那样等到老年代几乎填满再进行回收,而是当堆内存使用率达到某一阈值时,便开始进行回收
- 要是CMS运行期间预留的内存无法满足程序需要,就会出现一次Concurrent Mode Failure失败,这时虚拟机启用备用方案,临时启用Serial old 收集器来重新进行老年代的垃圾收集,这样停顿时间就长了
- CMS采取标记清除法算法,会产生内存碎片,只能够选择空闲列表执行内存分配
优点:
为什么使用标记清除法?
因为并发清除时,如果用压缩整理内存,原来的用户线程使用的内存就无法使用了。标记压缩更适合STW场景下使用
::并发标记,会带来什么问题?
多标,会产生浮动垃圾。(这里多标,指的是标记线程多标记了一些黑色或者灰色的空间(详见 三色标记法))
漏标,原本应该存活的对象标记为已消亡(漏标)这就回带来问题了,一个需要被引用的对象被回收了,那程序返回的结果一定是有问题的。
::CMS如何解决漏标问题?
增量更新(Incremental Update):就是当黑色对象插入新的指向白色对象的引用关系时, 就将这个新插入的引用记录下来,等并发扫描结束之后, 再将这些记录过的引用关系中的黑色对象为根, 重新扫描一次(重新标记阶段)。 这可以简化理解为, 黑色对象一旦新插入了指向白色对象的引用之后, 它就变回灰色对象了
::三色标记法
::设置参数
- -XX:+UseConcMarkSweepGC 开启后,自动将-XX:UseParNewGC打开,即ParNew(Young区)+CMS(old区)+Serial GC组合
- -XX:CMSlnitiatingOccupanyFraction 设置堆内存使用率的阈值,一旦达到该阈值,则开始进行回收 jdk5及之前默认68,jdk6及以上92,即老年代的空间使用率达到68%时会执行一次CMS回收 如果内存增长缓慢,可以设置一个稍大的值,有效降低CMS的触发频率,减少老年代回收的次数 如果应用程序内存使用率增加很快,则应该降低这个阈值,以避免频繁触发老年代串行收集器
- -XX:+UseCMSCompactAtFullCollection 用于执行完Full GC后对内存空间进行压缩整理 不过内存压缩无法并发执行,会带来停顿时间更长的问题
- -XX:CMSFullGCsBeforeCompaction 设置执行多少次FullGC后对内存空间进行压缩整理
- -XX:ParallelCMSThreads 设置CMS的线程数量 默认启动的线程数是(ParallelGCThreads(年轻代并行收集器的线程数)+3)/4