1、CMS的两种模式与一种特殊策略:
Backgroud CMS :
CMS回收流程
官网
: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html#concurrent_mark_sweep_cms_collectorCMS(Concurrent Mark Sweep)收集器是一种以获取
最短回收停顿时间
为目标的收集器。采用的是"标记-清除算法",整个过程分为4步
(1)初始标记 CMS initial mark 标记GC Roots直接关联对象,不用Tracing,速度很快
(2)并发标记 CMS concurrent mark 进行GC Roots Tracing
(3)重新标记 CMS remark 修改并发标记因用户程序变动的内容
(4)并发清除 CMS concurrent sweep 清除不可达对象回收空间,同时有新垃圾产生,留着下次清理称为浮动垃圾
由于整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行的。
优点:并发收集、低停顿
缺点:产生大量空间碎片、并发阶段会降低吞吐量
第一个问题:为什么我的CMS回收流程图上初始标记是单线程,为什么不使用多线程呢?
初始化标记阶段是串行的,这是JDK7的行为。JDK8以后默认是并行的,可以通过参数
-XX:+CMSParallelInitialMarkEnabled控制
Foregroud CMS:
其实这个也是CMS一种收集模式,但是他是并发失败才会走的模式。这里聊到一个概念,什么是并发失败呢?
并发失败官方的描述是:
如果 并发搜集器不能在年老代填满之前完成不可达(unreachable)对象的回收 ,或者 年老代中有效的空闲内存空间不能满足某一个内存的分配请求 ,此时应用会被暂停,并在此暂停期间开始垃圾回收,直到回收完成才会恢复应用程序。这种无法并发完成搜集的情况就成为 并发模式失败(concurrent mode failure) ,而且这种情况的发生也意味着我们需要调节并发搜集器的参数了。
简单来说,也就是我去进行并发标记的时候,内存不够了,这个时候我会进入STW,并且开始全局Full GC.
那么什么时候会进行并发失败呢 换句话说,我们的难道非要满了之后才进行收集
-XX:CMSInitiatingOccupancyFraction
-XX:+UseCMSInitiatingOccupancyOnly
注意:-XX:+UseCMSInitiatingOccupancyOnly 只是用设定的回收阈值(上面指定的70%),如果不指定,JVM仅在第一次使用设定值,后续则自动调整.这两个参数表示只有在Old区占了CMSInitiatingOccupancyFraction设置的百分比的内存时才满足触发CMS的条件。注意这只是满足触发CMS GC的条件。至于什么时候真正触发CMS GC