jq执行2次同样的方法怎么让第一次执行的不触发_你不知道的CMS GC
在G1出来之前,CMS绝对是OLTP系统的标配。即使G1出来几年了,生产环境很多的JVM实例还是采用ParNew+CMS的组合。但是即使其得到这么广泛的应用,还是有很多同学对它有很深的误解。本文主要对ParNew+CMS经典组合下,触发的几种垃圾回收方式进行几个概念的纠正。
Backgroud
可能更多人只知道CMS,而不知道Backgroud CMS。事实上我们说的CMS,即包含了5个阶段的CMS,就是Background CMS,如下图所示:
说明:
- 图中初始化标记阶段是串行的,这是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的C4是完全并发的。
为什么有个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前提下有三种可能:
- 上一次CMS并发GC执行过后,再执行参数-XX:CMSFullGCsBeforeCompaction=0指定的Full GC次数,0表示每次FullGC后都会压缩,同时0也是默认值;
- 调用了System.gc(),当然这就要满足-XX:-DisableExplicitGC;
- 晋升担保失败,即预计Old区没有足够空间来容纳下次YoungGC晋升的对象;
HOW?
碎片化问题一直是CMS采用的标记清理算法最让人诟病的地方:Backgroud CMS采用的标记清理算法会导致内存碎片问题,从而埋下发生FullGC导致长时间STW的隐患。
FullGC这么恐怖,有办法缓解么,或者说尽量避免它在白天,甚至业务高峰期出现?有!笔者给你分享一个歪门邪道,不记得是多少年前,在哪里道听途说才得到这个偏方的,而且据说以前阿里的一些业务也用了这个偏方,不管是哪里得来的偏方,反正肯定有用的。这个偏方很简单:在业务最低峰期(比如大陆的很多业务可以选在凌晨2,3点夜深人静的时候)强行触发FullGC(需要结合参数-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0,这两个参数默认值就是这样的,表示触发FullGC时压缩堆),从而优化内存碎片并压缩堆,降低在业务高峰期发生FullGC的概率(只能降低,不能杜绝)。
可能还有一小部分同学连强行触发FullGC都不知道,笔者好人做到底,送佛送到西:
# 没有开启-XX:+DisableExplicitGC的前提下调用System.gc()就会发生FullGCSystem.gc();或者通过jmap命令触发:# jmap -histo:live pid
总结
按照惯例,最后来个总结:
- 正常情况下触发Backgroud模式的CMS GC,这是并发模式收集,对业务影响很小,你好我好都好。
- 当并发模式搞不定了,就会退化成Foreground模式,这个回收过程业务线程是不可用的,这时候就触发了FullGC。
- 接下来根据是否满足上面提到几个条件决定是否采用MSC算法压缩堆。
- CMSFullGCsBeforeCompaction决定多少次FullGC后压缩堆,具体配置多大,由你决定,但是不建议太大,否则在采用MSC算法压缩堆之前,由于内存碎片的问题,导致出现promotion failure,总之这是trade-off。
关注我,后续更多干货奉上!
jq执行2次同样的方法怎么让第一次执行的不触发_你不知道的CMS GC相关推荐
- jq执行2次同样的方法怎么让第一次执行的不触发_他们说,这段代码你能看得懂她的开始,却猜不中她的结尾。...
看下小姐姐,舒缓下心情先. 好,现在回到我们的主题,看下下面这段代码,你觉得它会输出几个#号呢? 这个问题来自于我们技术群里的一位同学的提问,为了给大家一个思考时间,我们先不说结果,先再看下另一位可爱 ...
- JavaScript 自执行函数和 jQuery扩展方法
我们通常将JS代码写在一个单独的JS文件中,然后在页面中引入该文件.但是,有时候引入后会碰到变量名或函数名与其它JS代码冲突的问题.那么如何解决这个问题呢?作用域隔离.在JS中,作用域是通过函数来划分 ...
- shiro和Spring整合使用注解时没有执行realm的doGetAuthorizationInfo回调方法的解决
shiro和Spring整合使用注解时没有执行realm的doGetAuthorizationInfo回调方法的解决 from :http://blog.csdn.net/babys/article/ ...
- python子进程通信_python执行子进程实现进程间通信的方法
本文实例讲述了python执行子进程实现进程间通信的方法.分享给大家供大家参考.具体实现方法如下: a.py: import subprocess, time subproc = subprocess ...
- layui表单提交使用form.on(‘submit(sub)‘,function (){}) 使用ajax请求时回调不执行的原因及解决方法
layui表单提交使用form.on('submit(sub)',function (){}) 使用ajax请求时回调不执行的原因及解决方法 参考文章: (1)layui表单提交使用form.on(' ...
- python源程序执行的方式是什么执行-python调用可执行文件的方法
最近要用到python调用C程序,因此,看了一下python调用别的程序的方法.大致来说,python调用C/C++有两种方式,一种是调用C编译的动态链接库,即so文件,一种是调用C生成的可执行文件. ...
- python 命令-Python中执行系统命令的四种方法
一.os.system方法 在子终端运行系统命令,可以获取命令执行后的返回信息以及执行返回的状态.执行后返回两行结果,第一行是结果, 第二行是执行状态信息,如果命令成功执行,这条语句返回0,否则返回1 ...
- python自带的shell是什么-python中执行shell的两种方法总结
一.使用python内置commands模块执行shell commands对Python的os.popen()进行了封装,使用SHELL命令字符串作为其参数,返回命令的结果数据以及命令执行的状态: ...
- 解决 C/C++ 程序执行后控制台一闪而过的方法
解决 C/C++ 程序执行后控制台一闪而过的方法(1-20190305) 文章目录: 一.解决方法一: 二.解决方法二: 最近开始学习C++,不学习真的找不到太好的工作,还容易被淘汰,其实说实话我是真 ...
最新文章
- 强化学习(三) - Gym库介绍和使用,Markov决策程序实例,动态规划决策实例
- laravel实现读写分离
- C++:友元(非成员友元函数、成员友元函数、友元类)
- 我的WCF之旅(1):创建一个简单的WCF程序
- java流类图结构_java学习之IO流(学习之旅,一)
- 部分IE8使用的兼容CSS3属性的方法
- CVPR 2020 | 序列化的三维形状生成网络PQ-NET
- oracle 创建数据库表 如果此表存在则删除后再重建
- linuxYUM源配置问题
- 汽车方向盘电子助力转向器如何接线_案例 | 看3D打印如何助力汽车电子连接器模具冷却水路的设计优化...
- 21岁开始练字晚不晚?
- vue3 + router-view + keepalive parentComponent.ctx.deactivate is not a function
- set的用法及短语_set的用法和例句
- ***/BandwagonHost选择Linux操作系统的技巧
- Java 实现顺时针螺旋二维数组输出
- android 主流机型排行榜,安卓手机排行榜
- Python3.5 Django1.10 Scrapy1.2 Ubuntu16.04 HTML5
- Linux下搭建第一个区块链网络(FISCO BCOS)
- 北邮计算机学硕读博,博士生考试_考博经验——说说我北邮北航考博经历_沪江英语...
- 计算机网络在财务管理中的运用,浅析如何应用计算机网络进行财务管理