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