线上Tomcat升级到7.0.52,应用JVM FullGC变频繁,高峰期socket连接数,Cpu使用率都暴增。
思路
1.(排出问题优先级) Tomcat本身代码没有问题,可能是应用代码升级,或者环境改变
2.(找到问题)先把应用的heap dump下来分析下:
jmap -dump:format=b,file=path pid
用IBM的Heap Analyser分析,发现dubbo rpc调用的RpcInvocation对象和taglibs的SimpleForEachIterator对象占用了很大部分内存。
3.(分析问题)正常这两种类型很快被回收掉,怎么占那么大?有别的对象引用它们,导致不能释放?
1)发现RpcInvocation对象都是root refer(根对象),正常很快就被回收
2)再查看应用的JVM参数:
-Xms2g -Xmx2g -Xmn256m -XX:SurvivorRatio=8 -XX:ParallelGCThreads=8 -XX:PermSize=512m -XX:MaxPermSize=512m -Xss256k -XX:-DisableExplicitGC -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled
首先发现应用的新生代,即-Xmn256m 设置得太小了。对照上面RpcInvocation对象占用了226M,SimpleForEachIterator占用了267M内存。
新生代放不下,被放老生代
4.(验证分析对错)既然RpcInvocation对象和SimpleForEachIterator对象应该都是可以很快被回收了,那么思路变成,触发一下线上的FullGC,看下对象有没有被回收。
在触发之前,先用jmap -histo pid统计下对象的数量:
34: 136762 4376384 com.alibaba.dubbo.rpc.RpcInvocation
129: 16345 392280 org.apache.taglibs.standard.tag.common.core.ForEachSupport$SimpleForEachIterator
用 jmap -histo:live 触发Full GC之后:
294: 625 20000 com.alibaba.dubbo.rpc.RpcInvocation
495: 292 7008 org.apache.taglibs.standard.tag.common.core.ForEachSupport$SimpleForEachIterator
果然数量大大的减少了。
所以结论比较明显了,新生代(Young generation)的空间太小,导致有一些本应该可以很快就被回收的对象被放到了老生代(Old generation)里,导致老生代上涨很快,频繁Full GC。
5.(解决问题)于是想办法增加新生代的大小,把JVM参数改为: -Xms2g -Xmx2g -XX:ParallelGCThreads=8 -XX:PermSize=256m -XX:MaxPermSize=512m -Xss256k -XX:-DisableExplicitGC -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled
因为观察到PermSize实际上只用了不到200M,没有必要设置为512M,浪费内存,所以改为 -XX:PermSize=256m -XX:MaxPermSize=512m 。
另外,把新生代最大限制-Xmn256m 去掉。因为默认的NewRatio = 2,即除了PermSize,新生代大约占内存的1/3,即约(2048 - 256) /3 = 597M。和原来相比增大了一倍不止。
总结
Permanent Space开始时分配足够大空间,可不管。YGC算法很快
理想的GC/内存使用情况
Old Space增长缓慢,FullGC次数少,。FullGC的时间短(大部情况应该要在1秒内)。
GC调优就是一个取舍权衡的过程,有得必有失,最好可以在多个不同的实例里,配置不同的参数,然后进行比较。
https://blog.csdn.net/hengyunabc/article/details/24924843