【转载】为什么不建议<=3G的情况下使用CMS GC

之前曾经有讲过在heap size<=3G的情况下完全不要考虑CMS GC,在heap size>3G的情况下也优先选择ParallelOldGC,而不是CMS GC,只有在暂停时间无法接受的情况下才考虑CMS GC(不过当然,一般来说在heap size>8G后基本上都得选择CMS GC,否则那暂停时间是相当吓人的,除非是完全不在乎响应时间的应用),这其实也是官方的建议(每年JavaOne的GC Tuning基本都会这么讲)。

为什么给了一个这么“武断”的建议呢,不是我对CMS GC有什么不爽,相反CMS GC一直是我很热爱的一种GC实现,之所以建议在<=3G的情况下完全不要考虑CMS GC,主要出于以下几点考虑:

1、触发比率不好设置

在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来完成回收动作,这个时候就慢的离谱了。

2、抢占CPU

    CMS GC大部分时间和应用是并发的,所以会抢占应用的CPU,通常在CMS GC较频繁的情况下,可以很明显看到一个CPU会消耗的非常厉害。

3、YGC速度变慢
    由于CMS GC的实现原理,导致对象从新生代晋升到旧生代时,寻找哪里能放下的这个步骤比ParallelOld GC是慢一些的,因此就导致了YGC速度会有一定程度的下降。

4、碎片问题带来的严重后果

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])来避免碎片问题,但这显然是一个很龌蹉的办法(因为同样会对心跳或维持状态的分布式场景造成影响)。

5、CMS GC的”不稳定“性

如果关注过我在之前的blog记录的碰到的各种Java问题的文章(可在此查看),就会发现碰到过很多各种CMS GC的诡异问题,尽管里面碰到的大部分BUG目前均已在新版本的JVM修复,但谁也不知道是不是还有问题,毕竟CMS GC的实现是非常复杂的(因为要在尽可能降低应用暂停时间的情况下还保持对象引用的扫描不要出问题),而ParallelOldGC的实现相对是更简单很多的,因此稳定性相对高多了。 而且另外一个不太好的消息是JVM Team的精力都已转向G1GC和其他的一些方面,CMS GC的投入已经很少了(这也正常,毕竟G1GC确实是方向)。

在大内存的情况下,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

原文链接:http://gao-xianglong.iteye.com/blog/2179252

另对于大规模分布式性能优化请参阅:http://gao-xianglong.iteye.com/blog/2223170

时间: 2024-08-10 15:33:08

【转载】为什么不建议<=3G的情况下使用CMS GC的相关文章

Android socket在系统休眠情况下调研

做了3年的IM应用,一直没有确认过socket在系统休眠的情况下会不会就收不到消息了,网上也搜过一些资料说android手机分为AP和BP两个部分,系统休眠的时候AP是休眠的,而BP是不休眠的,网络协议栈是运行在BP层的,所以当BP收到数据包的时候,系统会唤醒AP,但是AP运行的时间是很短的.虽然听起来很有道理的样子,但是没有亲手测试过,还是一块心病~~~,今天又想起这事,索性动手自己写代码测试看看结果. Server端code: public class TestServer { public

socket在系统休眠情况下调研【转】

做了3年的IM应用,一直没有确认过socket在系统休眠的情况下会不会就收不到消息了,网上也搜过一些资料说android手机分为AP和BP两个部分,系统休眠的时候AP是休眠的,而BP是不休眠的,网络协议栈是运行在BP层的,所以当BP收到数据包的时候,系统会唤醒AP,但是AP运行的时间是很短的.虽然听起来很有道理的样子,但是没有亲手测试过,还是一块心病~~~,今天又想起这事,索性动手自己写代码测试看看结果. Server端code: public class TestServer { public

编写高质量代码改善C#程序的157个建议——建议17:多数情况下使用foreach进行循环遍历

建议17:多数情况下使用foreach进行循环遍历 由于本建议涉及集合的遍历,所以在开始讲解本建议之前,我们不妨来设想一下如何对结合进行遍历.假设存在一个数组,其遍历模式可以采用依据索引来进行遍历的方法:又假设存在一个HashTable,其遍历模式可能是按照键值来进行遍历.无论是哪个集合,如果他们的遍历没有一个公共的接口,那么客户端在进行遍历时,相当于是对具体类型进行了编码.这样一来,当需求发生变化时,必须修改我们的代码.而且,由于客户端代码过多地关注了集合内部的实现,代码的可移植性就会变得很差

技术更新如此快的情况下,给程序员的一点建议

昨天老婆说,你永远不知道未来是什么样子,儿子将来的用的技术,与现在的完全是不同的. 这里我还真有点要说的,其实我是真的什么都没教儿子--有点冤. 我只想教他如何吸烟,就我本人来说,因为五岁吸过一根烟,所以才产生了一生的免疫.想抽就抽,不想抽就不抽. 另外,也想教他玩几个电子游戏,因为小时候接触,都会产生一生免疫. 当然,这些直接就被老婆否了.~~,想起有个医生发明了一个论点:吃鼻咖,能加强免疫.他首先想到拿他女儿做实验,你猜怎么着?当然是被他领导否了. ---------------------

编写高质量代码改善C#程序的157个建议——建议16:元素数量可变的情况下不应使用数组

建议16:元素数量可变的情况下不应使用数组 在C#中,数组一旦被创建,长度就不能改变.如果我们需要一个动态且可变长度的集合,就应该使用ArrayList或List<T>来创建. 而数组本身,尤其是一维数组,在遇到要求高效率的算法时,则会专门被优化以提升其效率.一维数组也成为向量,其性能是最佳的,在IL中使用了专门的指令来 处理它们(如newarr.ldelem.ldelema.ldelen和stelem). 从内存的使用角度来讲,数组在创建时被分配了一段固定长度的内存.如果数组的元素是值类型,

哪些情况下会导致重排或重绘的发生?请给出性能优化的建议。

1.简述重排的概念浏览器下载完页面中的所有组件(HTML.JavaScript.CSS.图片)之后会解析生成两个内部数据结构(DOM树和渲染树),DOM树表示页面结构,渲染树表示DOM节点如何显示.重排是DOM元素的几何属性变化,DOM树的结构变化,渲染树需要重新计算.2.简述重绘的概念重绘是一个元素外观的改变所触发的浏览器行为,例如改变visibility.outline.背景色等属性.浏览器会根据元素的新属性重新绘制,使元素呈现新的外观.由于浏览器的流布局,对渲染树的计算通常只需要遍历一次就

关于socket阻塞与非阻塞情况下的recv、send、read、write返回值(转载)

1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回值 <0时并且(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)的情况下认为连接是正常的,继续接收.只是阻塞模式下recv会阻塞着接收数据,非阻塞模式下如果没有数据会返回,不会阻塞着读,因此需要 循环读取 2.阻塞模式与非阻塞模式下writ

如何在没有实际项目经验的情况下找到工作

原文:How to Land a Development Job Without Experience 作者:Paddy Sherry 译者:LeviDing 声明:转载请注明出处. ??许多开发人员在找工作的时候,虽然满足了对方所要求的理论技能,但是缺乏实际的开发经验,这让雇主在是否雇用你这个问题上犹豫不决.在这篇文章中,具有丰富招聘经验的 Paddy Sherry 为你提供了一些指南,来帮助你提高找到工作的体会. ??对于许多年轻的计算机或 IT 相关专业毕业生,在没有实际项目开发经验的情况

0028-如何在CDH未启用认证的情况下安装及使用Sentry

温馨提示:要看高清无码套图,请使用手机打开并单击图片放大查看. 1.文档编写目的 CDH平台中的安全,认证(Kerberos/LDAP)是第一步,授权(Sentry)是第二步.如果要启用授权,必须先启用认证.但在CDH平台中给出了一种测试模式,即不启用认证而只启用Sentry授权.但强烈不建议在生产系统中这样使用,因为如果没有用户认证,授权没有任何意义形同虚设,用户可以随意使用任何超级用户登录HiveServer2或者Impala,并不会做密码校验.注:本文档仅适用于测试环境. 本文档主要描述如