记一次OOM排查解决

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次OOM排查解决相关的知识,希望对你有一定的参考价值。

现场人员反馈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问题解决。




以上是关于记一次OOM排查解决的主要内容,如果未能解决你的问题,请参考以下文章

记一次OOM排查过程

生产事故-记一次特殊的OOM排查

记一次外部agent侵入导致的OOM排查过程

记一次 android 线上 oom 问题

记一次线上机器CPU飙高的排查过程

记一次死锁问题的排查和解决