之前曾经有讲过在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

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

  1. jvm在什么情况下会执行GC

    jvm在什么情况下会执行GC?[五种情况] 对象没有引用 作用域发生未捕获异常 程序在作用域正常执行完毕 程序执行了System.exit() 程序发生意外终止(被杀进程等) 什么是没有对象引用?

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

    今天是我看<编写高质量代码:改善C#程序的157个建议>第二遍的时候了,看完这本书的确是受益匪浅,学到了很多东西,也明白了很多道理. 里面的代码我每个都调试了一遍,有时候是有些出入的,可能 ...

  3. StoryBoard不使用AutoLayout情况下 按比例快速兼容适配iPhone6/6 Plus教程【转载】

    StoryBoard不使用AutoLayout情况下 按比例快速兼容适配iPhone6/6 Plus教程[转] 声明:本文章是为了后期快速兼容6和6Plus的按比例放大方法,对于部分读者来说可能觉得该 ...

  4. 关于JDBC技术中,调用MySQL中不建议在没有服务器身份验证的情况下建立SSL连接错误解决

    今天学习到了JBDC前沿:对JDBC编写步骤的封装,出现了一大串红色报错(当然,也不能叫报错,毕竟不是所有的红色都是错误eeror,) 错误如下: Establishing SSL connectio ...

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

    建议17:多数情况下使用foreach进行循环遍历 由于本建议涉及集合的遍历,所以在开始讲解本建议之前,我们不妨来设想一下如何对结合进行遍历.假设存在一个数组,其遍历模式可以采用依据索引来进行遍历的方 ...

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

    建议16:元素数量可变的情况下不应使用数组 在C#中,数组一旦被创建,长度就不能改变.如果我们需要一个动态且可变长度的集合,就应该使用ArrayList或List<T>来创建. 而数组本身 ...

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

    1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回值  ...

  8. java 23种设计模式,一般情况下,常用的有哪些? 转载

    原址:http://wangle.iteye.com/blog/196972 工厂模式, 工厂方法模式,单例模式, 外观(Facade)模式, 观察者(Observer)模式,桥接(Bridge)模式 ...

  9. [转载]什么情况下应该设置 cudnn.benchmark = True?

    总的来说,大部分情况下,设置这个 flag 可以让内置的 cuDNN 的 auto-tuner 自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题. 一般来讲,应该遵循以下准则: 如果网络的输 ...

随机推荐

  1. 【原】Redis-LRU缓存

    Redis高级篇 Redis-LRU缓存 将Redis作为缓存使用时,有时添加新数据时,旧数据是很难被清空的. LRU(Least Recently Used) 近期最少使用算法是常用算法之一. 最大 ...

  2. Ajax解决缓存的5种方法

    原文:http://www.ido321.com/129.html 1.在ajax发送请求前加上 anyAjaxObj.setRequestHeader(“If-Modified-Since”,”0″ ...

  3. Vijos1404 遭遇战 最短路,dijkstra,堆

    P1404遭遇战 标签:[显示标签]     背景 你知道吗,SQ Class的人都很喜欢打CS.(不知道CS是什么的人不用参加这次比赛). 描述 今天,他们在打一张叫DUSTII的地图,万恶的恐怖分 ...

  4. Windows下ffmpeg的完美编译

    纠结了好几天,终于搞定了,小结一下. 1.下载ffmpeg源码,官网 2.编译环境Msys的安装配置,http://blog.csdn.net/jszj/article/details/4028716 ...

  5. 【解决】国内访问github过慢

    github在国内慢的有点不能忍了,受不了了google了一下有什么方法没,还真找到一些方法. 死马当活马医,操作完之后确实速度上快了一些,但是毕竟国情所限,仍然做不到“秒开”. 主要是参考两篇博客: ...

  6. HW5.35

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  7. Android ADB使用

    ADB全称Android Debug Bridge, 是android sdk里的一个工具, 用这个工具可以直接操作管理android模拟器或者真实的andriod设备(如G1手机). 它的主要功能有 ...

  8. intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

    ActivityA到ActivityBintent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);//ActivityB不加入后退栈android:noHisto ...

  9. 转载 .net中的dll.refresh文件和pdb文件

    转载原地址: http://blog.csdn.net/lihuang319/article/details/6433727 dll.refresh文件 打开refresh文件,可以看到里面仅仅是个路 ...

  10. jsDoc注释的规范

    注释以/**  开始     */结束 JSDoc 命令属性 命令名 描述 @param @argument 指定参数名和说明来描述一个函数参数. @return @returns 描述函数的返回值. ...