前段时间在公司进行了GC的调优实践,记录一下供以后参考。基本上,和网上其他人提供的配置都差不多。
调优前情况:
采用并行收集器,系统TPS约600,为每隔15分钟左右会产生一次FullGC,FullGC的时间大约15秒,FullGC期间系统无法接收任何响应,操作系统的CPU使用率下降到5%一下(平时大约30%-40%)。
调整前JVM参数:
-server -D_Offline_FileDataArchive=true -Xms512m -Xmx2048m -Xss256k -XX:MaxPermSize=256m -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGCThreads=4 -XX:SurvivorRatio=16
调试过程:
1. 添加JVM参数,打开GC的log,发现-Xms设置为512m是比较合适的。
JVM参数:
-Xloggc:traf_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCTimeStamps
2.采用并发收集器,替代并行收集器,继续设置-Xms为512m
JVM参数:
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -Xnoclassgc
3. 发现时不时会在Old代GC时,系统会停止操作,无法接收任何响应,就像采用并行收集器的FullGC现象,gc的日志里显示“promotion failed”。原来是Old代在进行GC时,GC的收集速度小于Old的增加速度,导致系统彻底暂停下来,进行FullGC。
JVM参数:
-XX:CMSInitiatingOccupancyFraction=80
4. 发现PermGen的增长特别快,而且GC后,PermGen还在缓慢增加,最终导致PermGen爆满,系统停止运行。究其原因,是因为添加了-Xnoclassgc。 这个-Xnoclassgc是表示不多class进行垃圾回收,原本考虑class一旦load起来了,是很少会被回收的,但这只是自己毫无根据的假设。实际上,因为我们的代码里用到了Spring,hibernate,这些框架用到了很多反射,产生了大量临时的class,所以系统需要对class进行垃圾回收,-Xnoclassgc是绝不能打开的。
JVM参数:
-Xnoclassgc
调整后情况:
系统运行了3天,没有出现停机FullGC的现象,TPS提高倒不多大概到650左右。
调整后JVM参数:
-server -D_Offline_FileDataArchive=true -Xms2048m -Xmx2048m -Xmn512m -Xss256k -XX:MaxPermSize=256m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=6 -XX:MaxTenuringThreshold=7 -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:SoftRefLRUPolicyMSPerMB=0
关于GC分代垃圾回收过程的演示,JavaEve上找到一个很好的文章
http://chenchendefeng.iteye.com/blog/455883