为何不建议<=3G的状况下使用CMS GC

以前曾经有讲过在heap size<=3G的状况下彻底不要考虑CMS GC,在heap size>3G的状况下也优先选择ParallelOldGC,而不是CMS GC,只有在暂停时间没法接受的状况下才考虑CMS GC(不过固然,通常来讲在heap size>8G后基本上都得选择CMS GC,不然那暂停时间是至关吓人的,除非是彻底不在意响应时间的应用),这其实也是官方的建议(每一年JavaOne的GC Tuning基本都会这么讲)。 html

为何给了一个这么“武断”的建议呢,不是我对CMS GC有什么不爽,相反CMS GC一直是我很热爱的一种GC实现,之因此建议在<=3G的状况下彻底不要考虑CMS GC,主要出于如下几点考虑: 一、触发比率很差设置 在JDK 1.6的版本中CMS GC的触发比率默认为old使用到92%时,假设3G的heap size,那么意味着旧生代大概就在1.5G--2.5G左右的大小,假设是92%触发,那么意味着这个时候旧生代只剩120M--200M的大小,一般 这点大小颇有多是会致使不够装下新生代晋生的对象,所以须要调整触发比率,但因为heap size比较小,这个时候到底设置为多少是挺难设置的,例如我看过heap size只有1.5G,old才800m的状况下,还使用CMS GC的,触发比率仍是80%,这种状况下就悲催了,意味着旧生代只要使用到640m就触发CMS GC,只要应用里稍微把一些东西cache了就会形成频繁的CMS GC。 CMS GC是一个大部分时间不暂停应用的GC,就形成了须要给CMS GC留出必定的时间(由于大部分时间不暂停应用,这也意味着整个CMS GC过程的完成时间是会比ParallelOldGC时的一次Full GC长的),以便它在进行回收时内存别分配满了,而heap size原本就小的状况下,留多了嘛容易形成频繁的CMS GC,留少了嘛会形成CMS GC还在进行时内存就不够用了,而在不够用的状况下CMS GC会退化为采用Serial Full GC来完成回收动做,这个时候就慢的离谱了。 二、抢占CPU CMS GC大部分时间和应用是并发的,因此会抢占应用的CPU,一般在CMS GC较频繁的状况下,能够很明显看到一个CPU会消耗的很是厉害。 三、YGC速度变慢 因为CMS GC的实现原理,致使对象重新生代晋升到旧生代时,寻找哪里能放下的这个步骤比ParallelOld GC是慢一些的,所以就致使了YGC速度会有必定程度的降低。 四、碎片问题带来的严重后果 CMS GC最麻烦的问题在于碎片问题,一样是因为实现原理形成的,CMS GC为了确保尽量少的暂停应用,取消了在回收对象所占的内存空间后Compact的过程,所以就形成了在回收对象后整个old区会造成各类各样的不连续 空间,天然也就产生了不少的碎片,碎片会形成什么后果呢,会形成例如明明旧生代还有4G的空余空间,而新生代就算所有是存活的1.5g对象,也仍是会出现 promotion failed的现象,而在出现这个现象的状况下CMS GC多数会采用Serial Full GC来解决问题。 碎片问题最麻烦的是你彻底不知道它何时会出现,所以有可能会形成某天高峰期的时候应用忽然来了个长暂停,因而就悲催了,对于不少采用了相似心跳来维持 长链接或状态的分布式场景而言这都是灾难,这也是Azul的Zing JVM相比而言最大的优点(可实现不暂停的状况下完成Compact,解决碎片问题)。 目前对于这样的现象咱们惟一的解决办法都是选择在低峰期主动触发Full GC(执行jmap -histo:live [pid])来避免碎片问题,但这显然是一个很龌蹉的办法(由于一样会对心跳或维持状态的分布式场景形成影响)。 五、CMS GC的”不稳定“性 若是关注过我在以前的blog记录的碰到的各类Java问题的文章(可在此查 看),就会发现碰到过不少各类CMS GC的诡异问题,尽管里面碰到的大部分BUG目前均已在新版本的JVM修复,但谁也不知道是否是还有问题,毕竟CMS GC的实现是很是复杂的(由于要在尽量下降应用暂停时间的状况下还保持对象引用的扫描不要出问题),而ParallelOldGC的实现相对是更简单很 多的,所以稳定性相对高多了。
并且另一个不太好的消息是JVM Team的精力都已转向G1GC和其余的一些方面,CMS GC的投入已经不多了(这也正常,毕竟G1GC确实是方向)。 java

在大内存的状况下,CMS GC绝对是不二的选择,并且Java在面对内存愈来愈大的状况下,必须采用这种大部分时候不暂停应用的方式,不然Java之后就很是悲催了,G1GC在 CMS GC的基础上,有了不少的进步,尤为是会作部分的Compact,但仍然碎片问题仍是存在的,哎… 微信

Java如今在大内存的状况下还面临的另外两个大挑战:
1. 分析内存的堆栈太麻烦,例如若是在大内存的状况下出现OOM,那简直就是杯具,想一想dump出一个几十G的文件,而后还要分析,这得多长的时间呀,真心但愿JDK在这方面能有更好的工具…
2. 对象结构不够紧凑,致使在内存空间有很高要求的场景Java劣势明显,不过这也是新版本JDK会重点优化的地方。
至于在cpu cache miss等控制力度上不如C之类的语言,那是更没办法的,相比带来的开发效率提高,也只能认了,毕竟如今多数场景都是工程性质和大规模人员的场景,所以开发效率、可维护性会更重要不少。 架构

推荐几篇相关的文章:
1. A Generational Mostly-concurrent GC(CMS GC的理论论文)
2. The Pauseless GC Algorithm(能够管窥下Zing是如何实现不暂停compact的)
3. Understanding CMS GC log 并发

最近在纠结一个问题,求有想法或建议的回下消息。
在一个打某种日志的场景中,如何作到避免打日志致使应用受影响,首先异步等是确定的,但因为日志量巨大,因此仅仅异步仍是会形成很大的IO压力,但限流的 话到底怎么限比较合理呢?(例如根据IOPS?但IOPS的话还得获取硬件信息等,挺折腾,另外毕竟仍是想作到在能支撑的状况下尽量不要丢弃这些日志信 息),有此类场景经验来给点建议吧。 框架

=============================
欢迎关注微信公众号:hellojavacases less

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和你们一块儿讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。 异步

公众号上发布的消息都存放在http://hellojava.info上。 分布式

相关文章
相关标签/搜索