1. 程式人生 > >記一次OOM排查解決

記一次OOM排查解決

Hibernate 內存溢出 Hibernate緩存 OutOfMemoryError Java heap space

現場人員反饋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排查解決