承上启下,JDK9标记作废,JDK14删除

  1. 第一次让垃圾收集线程和用户线程(基本上)同时工作
  2. 标记算法(三色标记法)
  3. CMS 在小内存应用上的表现要优于 G1,而大内存应用上 G1 更有优势,大小内存的界限是6GB到8GB

  • 初始标记和重新标记阶段仍然需要STW机
  • 由于在垃圾收集阶段用户线程没有中断,所以在CMS回收过程中,还应该确保应用程序用户线程有足够的内存可用。因此CMS收集器不能像其他收集器那样等到老年代几乎填满再进行回收,而是当堆内存使用率达到某一阈值时,便开始进行回收
  • 要是CMS运行期间预留的内存无法满足程序需要,就会出现一次Concurrent Mode Failure失败,这时虚拟机启用备用方案,临时启用Serial old 收集器来重新进行老年代的垃圾收集,这样停顿时间就长了
  • CMS采取标记清除法算法,会产生内存碎片,只能够选择空闲列表执行内存分配

优点:

  1. 并发收集
  2. 低延迟
    缺点:
  3. 内存碎片化,采用标记清除法
  4. 无法处理浮动垃圾,只能等下一次处理

为什么使用标记清除法

因为并发清除时,如果用压缩整理内存,原来的用户线程使用的内存就无法使用了。标记压缩更适合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