快上网建站品牌

13518219792
  • 首页
  • 关于我们
    • 如何选择
    • 选择理由
  • 案例作品
    • 网站建设
    • 优化推广
    • 微信开发
    • 电商托管
  • 服务项目
    • 网站建设
    • 移动端/APP
    • 微信/小程序
    • 技术支持
    • 其它服务
  • 建站知识
    • 成都网站建设
    • 成都做网站
    • 成都网站设计
  • 网站售后
    • 成都网站运营
    • 成都网站维护
    • 成都网站推广
  • 客服中心
  • 全国分站

你不知道的CMSGC

在G1出来之前,CMS绝对是OLTP系统的标配。即使G1出来几年了,生产环境很多的JVM实例还是采用ParNew+CMS的组合。但是即使其得到这么广泛的应用,还是有很多同学对它有很深的误解。本文主要对ParNew+CMS经典组合下,触发的几种垃圾回收方式进行几个概念的纠正。

网站建设公司,为您提供网站建设,网站制作,网页设计及定制网站建设服务,专注于企业网站制作,高端网页制作,对玻璃隔断等多个行业拥有丰富的网站建设经验的网站建设公司。专业网站设计,网站优化推广哪家好,专业成都网站营销优化,H5建站,响应式网站。

Backgroud

可能更多人只知道CMS,而不知道Backgroud CMS。事实上我们说的CMS,即包含了5个阶段的CMS,就是Background CMS,如下图所示:

你不知道的CMS GC

说明:

  • 图中初始化标记阶段是串行的,这是JDK7的行为。JDK8以后默认是并行的,可以通过参数-XX:+CMSParallelInitialMarkEnabled控制。

  • 由图可知,CMS还有两个阶段是完全STW(Stop The World)的,即初始化标记和最终标记(重新标记)。

  • 其他阶段都是并发的,所以CMS被称为Concurrent Mark&Sweep,但是我认为前面还需要加个Mostly才是最贴切,即CMS是一个Mostly Concurrent Mark and Sweep Garbage Collector,因为它还没办法做到完全并发。

不只是CMS,就是G1,以及JDK11的ZGC都没有做到完全的并发。就目前笔者了解到的所有GC中,只有Azul的C四是完全并发的。

为什么有个Background关键词?我们都知道配置CMS垃圾回收的话,有两个重要参数:-XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly,这两个参数表示只有在Old区占了75%的内存时才满足触发CMS的条件。注意这只是满足触发CMS GC的条件。至于什么时候真正触发CMS GC,由一个后台扫描线程决定。CMSThread默认2秒钟扫描一次,判断是否需要触发CMS,这个参数可以更改这个扫描时间间隔,例如-XX:CMSWaitDuration=5000,此外可以通过jstack日志看到这个线程:

"Concurrent Mark-Sweep GC Thread" os_prio=2 tid=0x000000001870f800 nid=0x0f4 waiting on condition

Foregroud

这个名词第一次听笨神说的。当然笨神也不是随便自己捏造一个名词出来,这个名词来自于openjdk源码,参考concurrentMarkSweepGeneration.cpp:

void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) {
    case Resizing: {
        // nothing to be done in this state. 即这个阶段啥都没做
        _collectorState = Resetting;
        break;
    }  
    case Precleaning:
        // 预清理啥都没干
    case AbortablePreclean:
        // Elide(省略,取消的意思,相当于这个阶段也啥都没做) the preclean phase
        _collectorState = FinalMarking;
        break;
    default:
        ShouldNotReachHere();
}

源码比较多,我就不全部贴出来的,有兴趣的同学可以自己下载源码查看。

它发生的场景,比如业务线程请求分配内存,但是内存不够了,于是可能触发一次CMS GC,这个过程就必须要等待内存分配成功后业务线程才能继续往下面走,因此整个过程必须STW,所以这种CMS GC整个过程都是STW,但是为了提高效率,它并不是每个阶段都会走的,只走其中一些阶段,通过上面的源码可知,这些省下来的阶段主要是并行阶段:Precleaning、AbortablePreclean,Resizing。但不管怎么说如果走了类似foreground这种CMS GC,那么整个过程业务线程都是不可用的,效率会影响挺大。

foreground收集模式事实上就是发生了FullGC,由这段的分析可知FullGC相比CMS Backgroud  collect模式差距还是非常大的。

如果触发了FullGC,那就是ParNew+CMS组合最糟糕的情况。因为这个时候并发模式已经搞不定了,而且整个过程单线程,完全STW,甚至可能还会压缩堆(是否压缩堆在后面的MSC段落说明),真的不能再糟糕了!想象一下如果这时候业务量比较大,由于FullGC导致服务完全暂停几秒钟,甚至上10秒,对用户体验影响得多大。

另外,别以为G1就好很多,G1的FullGC同样是垃圾级别的存在:

The G1 garbage collector is designed to avoid full collections, but when the concurrent collections can't reclaim memory fast enough a fall back full GC will occur. The current implementation of the full GC for G1 uses a single threaded mark-sweep-compact algorithm.

原文出自:http://openjdk.java.net/jeps/307

MSC

MSC的全称是Mark Sweep Compact,即标记-清理-压缩,MSC是一种算法,请注意Compact,即它会压缩整理堆,这一点很重要。

这是foreground CMS在特定情况下才会采用的一种垃圾回收算法。至于什么时候会采用MSC进行压缩呢,请看源码,依然在concurrentMarkSweepGeneration.cpp中:

//a method used by foreground collection to determine what type of collection 
//(compacting or not, continuing or fresh)it should do.
void CMSCollector::decide_foreground_collection_type(){
  ... ... 
  *should_compact =
    UseCMSCompactAtFullCollection &&
    ((_full_gcs_since_conc_gc >= CMSFullGCsBeforeCompaction) ||
     GCCause::is_user_requested_gc(gch->gc_cause()) ||
     gch->incremental_collection_will_fail(true /* consult_young */));    
  ... ... 
}

由这段源码可知,foreground收集模式下如果采用MSC算法的压缩模式,那么在-XX:+UseCMSCompactAtFullCollection前提下有三种可能:

  1. 上一次CMS并发GC执行过后,再执行参数-XX:CMSFullGCsBeforeCompaction=0指定的Full GC次数,0表示每次FullGC后都会压缩,同时0也是默认值;

  2. 调用了System.gc(),当然这就要满足-XX:-DisableExplicitGC;

  3. 晋升担保失败,即预计Old区没有足够空间来容纳下次YoungGC晋升的对象;

HOW?

碎片化问题一直是CMS采用的标记清理算法最让人诟病的地方:Backgroud CMS采用的标记清理算法会导致内存碎片问题,从而埋下发生FullGC导致长时间STW的隐患。

FullGC这么恐怖,有办法缓解么,或者说尽量避免它在白天,甚至业务高峰期出现?有!笔者给你分享一个歪门邪道,不记得是多少年前,在哪里道听途说才得到这个偏方的,而且据说以前阿里的一些业务也用了这个偏方,不管是哪里得来的偏方,反正肯定有用的。这个偏方很简单:在业务最低峰期(比如大陆的很多业务可以选在凌晨2,3点夜深人静的时候)强行触发FullGC(需要结合参数-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0,这两个参数默认值就是这样的,表示触发FullGC时压缩堆),从而优化内存碎片并压缩堆,降低在业务高峰期发生FullGC的概率(只能降低,不能杜绝)。

可能还有一小部分同学连强行触发FullGC都不知道,笔者好人做到底,送佛送到西:

# 没有开启-XX:+DisableExplicitGC的前提下调用System.gc()就会发生FullGC
System.gc();

或者通过jmap命令触发:
# jmap -histo:live pid

总结

按照惯例,最后来个总结:

  • 正常情况下触发Backgroud模式的CMS GC,这是并发模式收集,对业务影响很小,你好我好都好。

  • 当并发模式搞不定了,就会退化成Foreground模式,这个回收过程业务线程是不可用的,这时候就触发了FullGC。

  • 接下来根据是否满足上面提到几个条件决定是否采用MSC算法压缩堆。

  • CMSFullGCsBeforeCompaction决定多少次FullGC后压缩堆,具体配置多大,由你决定,但是不建议太大,否则在采用MSC算法压缩堆之前,由于内存碎片的问题,导致出现promotion failure,总之这是trade-off。

本文题目:你不知道的CMSGC
当前链接:http://csdahua.cn/article/jjegec.html
扫二维码与项目经理沟通

我们在微信上24小时期待你的声音

解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流

其他资讯

  • c语言补0函数 c语言补空格和补零的区别
  • 高级语言c函数调用 c语言高级程序
  • php连接数据库获取数据 php连接数据库查询
  • php如何给请求返回数据 php返回数据给ajax
  • linux常用命令大数据 linux在大数据中的应用

行业动态

企业网站建设的重要性!

现在虽然是移动互联网时代,但企业网站依然重要,包含PC站点,移动站。可以说企业网站关系企业的未来发展和前途,尤其对中小企业更是如此,一些中小企业老板,对自己的名片很在乎,因为这是个门面。...

服务项目

  • 网站建设

    查看详情
  • 移动端/APP

    查看详情
  • 微信/小程序

    查看详情
  • 技术支持

    查看详情
  • 其它服务

    查看详情
  • 更多服务项目

    用我们的专业和诚信赢得您的信赖,从PC到移动互联网均有您想要的服务!

    获取更多

联系吧 在百度地图上找到我们

电话:13518219792

如遇占线或暂未接听请拨:136xxx98888

业务咨询 技术咨询 售后服务
网站制作
成都商城网站制作
网站制作报价
成都网站制作
移动手机网站制作
网站建设
成都网站建设
重庆教育培训网站建设
乐山网站建设
大足网站建设
网站设计
达州网站设计
广安网站设计
企业网站设计
高端网站设计
联系我们
电话:13518219792
邮箱:631063699@qq.com
地址:成都青羊区锦天国际1002号
网址:www.csdahua.cn

微信二维码

  • 友情链接
  • 电商网站建设
  • 成都网站建设
  • 郫县搬家公司
  • 快照排名
  • 成都网页设计
  • 成都网站建设
  • 四川发电机组
  • 成都网站建设公司
  • app开发公司
  • 宣传单印刷

Copyright © 2002-2023 www.csdahua.cn 快上网建站品牌 QQ:244261566 版权所有 备案号:蜀ICP备19037934号

  • 在线咨询
  • 13518219792
  • 微信二维码

  • 移动版官网