這周生產環境出了久違的
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
複製代碼