前端时间我们的服务器老收到报警短信,访问的时候又不慢(主要是7台服务器做了负载均衡,所以感觉不到问题),登录到服务器上看了下,GC出现了问题,
Java版本:
java version "1.6.0_32" Java(TM) SE Runtime Environment (build 1.6.0_32-b05) Java HotSpot(TM) 64-Bit Server VM (build 20.7-b02, mixed mode)
JVM参数:
-Xms16g -Xmx16g -Xmn2g -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:ParallelGCThreads=8 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:SurvivorRatio=4 -XX:MaxTenuringThreshold=10 -XX:CMSInitiatingOccupancyFraction=80
见图
一共有两个问题:
1)full gc提前了,我们设的是-XX:CMSInitiatingOccupancyFraction=80,当old区达到80%才进行一次cms gc,而现在25左右就开始了。
2)full gc时间过长,最近一次full gc花费了10几秒。
带着这两个问题进行排查:
用jstat查看最近一次full gc的原因,发现
导致频繁full gc的原来是System.gc(),在jvm参数里面添加-XX:+DisableExplicitGC,使用这个参数要防止NIO direct memory的OOM,可以观察服务器日志,当很长时间没有OOM,那就可以使用这个参数,不然可以用
-XX:+ExplicitGCInvokesConcurrent或 XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses,这两个参数也是用来改变System.gc()的默认行为用的;不同的是这两个参数只能配合CMS使用(-XX:+UseConcMarkSweepGC),而且System.gc()还是会触发GC的,只不过不是触发一个完全stop-the-world的full GC,而是一次并发GC周期。 CMS GC周期中也会做reference processing。
添加-XX:+DisableExplicitGC后,结果正常,可full gc的时间还是很长,观察GC日志,发现:
[1 CMS-remark: 10069518K(12582912K)] 12794124K(16078208K), 3.2904140 secs] [Times: user=22.29 sys=0.44, real=3.29 secs]
CMS-remark时间过长,添加-XX:+CMSScavengeBeforeRemark,这个参数是在CMS在做remark之前做一次YGC,最后问题终于解决,full gc时间只要100多毫秒。
不受报警短信的骚扰了。