【转载】为什么不建议<=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的)
原文链接:http://gao-xianglong.iteye.com/blog/2179252
另对于大规模分布式性能优化请参阅:http://gao-xianglong.iteye.com/blog/2223170
【转载】为什么不建议<=3G的情况下使用CMS GC的更多相关文章
- jvm在什么情况下会执行GC
jvm在什么情况下会执行GC?[五种情况] 对象没有引用 作用域发生未捕获异常 程序在作用域正常执行完毕 程序执行了System.exit() 程序发生意外终止(被杀进程等) 什么是没有对象引用?
- 编写高质量代码改善C#程序的157个建议:第17个建议之多数情况下使用foreach进行循环遍历
今天是我看<编写高质量代码:改善C#程序的157个建议>第二遍的时候了,看完这本书的确是受益匪浅,学到了很多东西,也明白了很多道理. 里面的代码我每个都调试了一遍,有时候是有些出入的,可能 ...
- StoryBoard不使用AutoLayout情况下 按比例快速兼容适配iPhone6/6 Plus教程【转载】
StoryBoard不使用AutoLayout情况下 按比例快速兼容适配iPhone6/6 Plus教程[转] 声明:本文章是为了后期快速兼容6和6Plus的按比例放大方法,对于部分读者来说可能觉得该 ...
- 关于JDBC技术中,调用MySQL中不建议在没有服务器身份验证的情况下建立SSL连接错误解决
今天学习到了JBDC前沿:对JDBC编写步骤的封装,出现了一大串红色报错(当然,也不能叫报错,毕竟不是所有的红色都是错误eeror,) 错误如下: Establishing SSL connectio ...
- 编写高质量代码改善C#程序的157个建议——建议17:多数情况下使用foreach进行循环遍历
建议17:多数情况下使用foreach进行循环遍历 由于本建议涉及集合的遍历,所以在开始讲解本建议之前,我们不妨来设想一下如何对结合进行遍历.假设存在一个数组,其遍历模式可以采用依据索引来进行遍历的方 ...
- 编写高质量代码改善C#程序的157个建议——建议16:元素数量可变的情况下不应使用数组
建议16:元素数量可变的情况下不应使用数组 在C#中,数组一旦被创建,长度就不能改变.如果我们需要一个动态且可变长度的集合,就应该使用ArrayList或List<T>来创建. 而数组本身 ...
- 关于socket阻塞与非阻塞情况下的recv、send、read、write返回值(转载)
1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回值 ...
- java 23种设计模式,一般情况下,常用的有哪些? 转载
原址:http://wangle.iteye.com/blog/196972 工厂模式, 工厂方法模式,单例模式, 外观(Facade)模式, 观察者(Observer)模式,桥接(Bridge)模式 ...
- [转载]什么情况下应该设置 cudnn.benchmark = True?
总的来说,大部分情况下,设置这个 flag 可以让内置的 cuDNN 的 auto-tuner 自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题. 一般来讲,应该遵循以下准则: 如果网络的输 ...
随机推荐
- 网页加载速度优化2--先加载css,然后再加载js文件。
网页加载时,是按从上到下,从左到右的顺序加载的.所以一定要先加载css文件(不要让用户看到一个杂乱无章的页面),最后再加载js文件,js一般都是处理功能的,所以不需要提前加载.先给用户观感,再给用户上 ...
- theano学习指南5(翻译)- 降噪自动编码器
降噪自动编码器是经典的自动编码器的一种扩展,它最初被当作深度网络的一个模块使用 [Vincent08].这篇指南中,我们首先也简单的讨论一下自动编码器. 自动编码器 文献[Bengio09] 给出了自 ...
- bzoj 3551 [ONTAK2010]Peaks加强版(kruskal,主席树,dfs序)
Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来 ...
- Android Studio工程导入另一个工程作为lib
简单视频应用开发时,使用Vitamio作为视频解码库,官方建议直接以工程作为lib方便升级,将该工程导入到项目时不知道该怎么做,参考了下面的博客,这里存档标记一下. 参考:导入一个Android St ...
- pip 安装python环境及打包
0.安装虚拟环境 pip install virtualenv virtualenv env1 source env1/bin/activate 1. 将包依赖信息保存在requireme ...
- RPi Debian Auto Login
This guide will show you how to login to a Debian image and start LXDE by simply powering the Pi on. ...
- 网吧局域网里的设置外网IP地址、设置内网IP地址、限制内网速度和路由器共享
现在啊,网吧的需求越来越高,同时在经济比较充裕的情况下,作为网吧的老板可能希望打造全千兆的网吧,让每个进入网吧的人都能充分体验高速的感觉,当然更重要的是在同行竞争中处于上游,特别是对网络游戏爱好者的吸 ...
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
ActivityA到ActivityBintent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);//ActivityB不加入后退栈android:noHisto ...
- Handlebar
1.Handlebar中文网: http://www.ghostchina.com/introducing-the-handlebars-js-templating-engine/ 2.http:// ...
- C++学习笔记(五):指针和引用
声明指针: //指针声明 * 号左右的空格是可选的,下面的定义都是正确的 int *pointer1; int* pointer2; int*pointer3; int * pointer4; //注 ...