11月
26
2013

一次CMS GC的调优工作

某台机器的内存比较大,之前的JVM参数是4G的堆,在压测过程中发现当QPS上来以后,Full GC会开始抬头,YoungGC的频率就不用说了,比较高。

观察GC日志和jstat -gcutil,感觉是QPS在峰值的时候对象创建比较多,也有大对象产生。于是打算加大堆的大小来延缓GC的时机,并且有一些GC参数的优化,反复调整后找到了一个适合我们的参数(没有一个best的参数,还是得按照应用的的情况去测量,最好是一遍压测一遍调整,最终找到一个best fit的参数组)。

在把堆调大的过程中比较担心下面几个问题:

1、GC的压力会不会增大?

2、一次GC的耗时会不会增加?

3、如果在GC stop-the-world的时间里,rt飙高怎么办?

这些问题最终都得到了解答,参考CMS GC的原理,结合jstat的观察,有了如下的结论。

新生代扩大3倍后,YoungGC每次会从root开始寻找存活的引用,而增大内存其实并不会导致存活对象增多(死亡对象是会增加的),因为只要你的QPS和rt是稳定的,那么同时存在的线程数也是稳定的,一个线程对应一个request,一个request中生成的对象相对是固定的,也就是说,只要QPS和rt稳定,只要内存足够,调的更大,其实正在处理的请求中的对象还是那么多,一次扫描的时间是不会明显增长的,所以往s0和s1拷贝的对象空间也是不会明显增长的,这导致YoungGC的开销和时间,其实并不会像配置的参数那样成倍增长。

而实际上,通过加大新生代的大小,YoungGC的频率明显减小,因为YoungGC是要stop-the-world的,所以应用停机的时间也会缩短。

旧生代的内存增大,可以避免QPS比较高时,内存迅速占满OldGen,触发Full GC。而对于CMS GC而言,因为上面说的新生代live对象不会明显增长,对remark阶段的耗时也是不会增长太多的,而CMS GC的sweep阶段是并发的,通过jstat可以看到Old区的占用百分比是慢慢减少的,sweep的过程对应用的rt影响不明显。

另外加入了-XX:+CMSScavengeBeforeRemark这个参数,用于在remark之前先做一次YoungGC,目的也是为了减少remark的时间,毕竟remark是要stop-the-world的。

Written by Hesey Wang in: Java,技术 |

6 Comments »

  • zxwu

    我们xmn设置2g,但当年轻代设大后,年轻代的垃圾收集时间增长比较大.楼主咋解决的?

    [回复]

    Hesey 回复:

    什么类型的系统?系统的请求量是否有增加?
    如文中说的,“只要QPS和rt稳定,正在处理的请求中的对象还是那么多”,MinorGC时间变长通常意味着YoungGen的Live Object变多了。

    [回复]

    Comment | 2014 年 05 月 01 日
  • Young GC会stop the world吗? 印象中,只有FullGC会。。

    [回复]

    Hesey Wang 回复:

    会的,只是因为通常几十毫秒就结束了,所以影响不大。最近遇到的一个case是young gc耗时1秒,stw的影响就很明显了

    [回复]

    liuinsect 回复:

    能具体说一下么? 几十毫秒已经很恐怖了啊

    [回复]

    Hesey Wang 回复:

    还好吧,和你young gen的live object大小有关,你可以看下gc log的时间

    Comment | 2014 年 05 月 08 日

RSS feed for comments on this post. TrackBack URL

Leave a comment

©2006 - 2016 Hesey (舒)