这周生产环境出了久违的
java.lang.OutOfMemoryError: Java heap space
,花了些时间找了下原因,记录分享一下 🥕
OOM分析
之前的jvm优化的文章中,有提到要增加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/login/gc
,这对于排查问题非常有帮助,当发生OOM时就会输出堆的内存快照(hprof文件)。
从生产环境拷贝出hprof文件后,就可以用MAT或者Jvisualvm来分析了,相对来说MAT更智能和易用一些。
用MAT打开hprof文件后,很明显可以看到(这里补充一个小插曲:在jdk11的环境下,MAT会报错无法打开,建议切回jdk8的环境打开MAT)
通过Leak Suspects其实已经可以看出问题所在了,SessionFactoryImpl
这个实例占用了87.48%的内存。很明显是内存泄漏了。
我们打开Histogram,可以看到类的实例数和所占的内存
这个看起来还并不是很清晰,可以排除软,弱,虚引用(剩下强引用)看的更加直观
现在就很明显了,SessionFactoryImpl
中的QueryPlanCache
造成了内存泄漏
QueryPlanCache内存泄漏解决
那什么是QueryPlanCache
呢,hibernate中的QueryPlanCache
会缓存sql,以便于后边的相同的sql重复编译。
如果in后的参数不同,hibernate会把其当成不同的sql进行缓存,从而缓存大量的sql导致heap内存溢出。
所以可以通过设置缓存最大值来进行限制,不设置默认是2G。
1 | spring: |