今年年初,公司的新平台上线之后,随着销售的推广,自4月份起,用户大幅增长,使用量急剧上升,导致部署单点登录服务的tomcat总是运行一段时间就宕掉,最近一段时间越来越频繁。
追踪了一下日志,应该是堆内存满导致tomcat宕掉的。
java.lang.OutOfMemoryError: Java heap space
第一反应是有大量对象的引用没释放,GC无法回收,结果heap满了,内存溢出。看了下tomcat启动配置, -Xmx给了1G,应该不算小了。(单点登录是在CAS上做的定制,认证会访问别的服务,Ticket都放在memCache里,所以1G肯定够用了)
又翻了翻日志,发现在即将宕掉之前,会频繁打印
java.lang.OutOfMemoryError:GC overhead limit exceeded
这个错误以前还真没见过,网上查了一下:
sun的说法: "if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown."
也就是,jvm gc行为中超过98%以上的时间去释放小于2%的堆空d间时会报这个错误。
感觉这不是主要问题,应该还是GC无法回收。日志看不出啥,还是老老实实用java heap dump出jvm内存镜像,看看是啥对象的引用没释放
jmap -dump:format=b,file=/path/file.hprof <pid>
执行这个命令时一定把服务下线,因为会导致目标服务被挂起。拿到镜像文件后,这里推荐一个工具,Eclipse Memory Analyzer,查看对象树和对象空间占用非常的方便。
发现Bouncycastleprovider对象占用了很多空间,查了下代码,是RSA加密时用到的,每次加密都会new BouncyCastleProvider(),应该就是这个对象无法被回收,导致内存溢出的。
改成单例的,从新发布,问题解决了。