现场人员反馈tomcat假死,已不能访问,而且一直报如下异常:
SEVERE:Memory usage is low, parachute is non existent, your system may start failing. java.lang.OutOfMemoryError: Java heap space
很显然堆内存溢出了,现场配置了2G的堆内存,用jmap命令dump heap失败,添加参数-F强制dump半天没有反应,只能带着-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tomcat/logs参数重启,过了半天问题又出现了,这次得到了堆内存的快照,用Memory Analyzer (MAT)分析,概要信息如下:
One instance of "org.hibernate.impl.SessionFactoryImpl" loaded by "org.apache.catalina.loader.WebappClassLoader @ 0x788c95390" occupies 1,567,956,008 (80.22%) bytes. The memory is accumulated in one instance of "java.util.concurrent.ConcurrentHashMap$Segment[]" loaded by "<system class loader>". Keywords org.hibernate.impl.SessionFactoryImpl org.apache.catalina.loader.WebappClassLoader @ 0x788c95390 java.util.concurrent.ConcurrentHashMap$Segment[]
从这个概要信息可以看到这个OOM是和Hibernate有关的。
视图Biggest Objects by Retained Size如下:
可以看到对象org.hibernate.impl.SessionFactoryImpl @ 0x78ada8e98持有的对象竟然站到了1.5GB的大小。视图Shortest Paths To the Accumulation Point如下:
从上图可以清晰的看出对象org.hibernate.impl.SessionFactoryImpl @ 0x78ada8e98、org.hibernate.stat.ConcurrentStatisticsImpl @ 0x78b1f2378、java.util.concurrent.ConcurrentHashMap @ 0x78b1f2928之间的引用关系。
视图Accumulated Objects in Dominator Tree如下:
从此图可以看到org.hibernate.stat.ConcurrentStatisticsImpl @ 0x78b1f2378对象持有了大量的ConcurrentHashMap对象,占到了整个堆内存的80%,导致了内存泄漏。经查类ConcurrentStatisticsImpl和Hibernate的SQL、HQL统计有关,Hibernate有个参数hibernate.generate_statistics,这个参数可以统计执行的SQL和HQL的执行信息,此参数默认是false,当设置为true时Hibernate就会缓存每一个执行的SQL和HQL,当大量请求访问,Hibernate就会缓存大量的SQL从而导致内存溢出,将此参数设置为false问题解决。
原文地址:http://blog.51cto.com/wenshengzhu/2086935