同事寫了一條 SQL,把 MyBatis 都幹翻了。。

作者:Lxlxxx
鏈接:https://juejin.cn/post/7221461552343072828

前言

繼上次線上CPU出現了報警,這次服務又開始整活了,風平浪靜了沒幾天,看生產日誌服務的運行的時候,頻繁的出現OutOfMemoryError,就是我們俗稱的OOM,這可還行!

頻繁的OOM直接會造成服務處於一個不可用的情況,通過Skywalking查看鏈路調用,基本全報紅了,基本處於一個癱瘓狀態,因爲生產該服務是分佈式部署,運維當即立斷對該服務進行重啓,因爲是B端的產品,先讓公司業務能用起來了,保證服務的正常使用,然後緊急查看問題,當然這個問題就來到了我這裏,既然分配給我了,咱高低給它查出來,並且修復了。

OutOfMemoryError出現的原因

先來了解下OutOfMemoryError出現的原因,無非就是兩類堆內存空間不足、元空間不足

  1. 堆內存空間不足:意味着程序存在一直有引用的對象(強引用),主要對象在引用的狀態就無法被GC回收,撐爆了-Xmx堆拓展的最大值,內存不足自然就會觸發堆內存溢出。
  2. 元空間:Java 8引入了元空間概念,代替了之前堆的永久代,由於元空間屬於堆外內存,不需要有對象引用,通過指針的方式表示類和元數據,之所以引用元空間就是一種JDK的升級優化,避免了永久代的內存溢出。

常見堆內存溢出的幾種情況

  1. 查詢數據庫返回的數據量過大,加載到內存中導致內存溢出;
  2. 代碼中出現死循環情況,導致大對象一直被引用不能被GC回收;
  3. 資源鏈接池、io流在使用完沒有進行手動釋放;
  4. 靜態集合類裏面存在引用對象,始終存在引用關係,沒有進行清除;

以上屬於常見的幾種堆內存溢出的場景,當然有時候我們的遇到的問題都是稀奇古怪的問題,常見的問題總是很少能遇到…

推薦一個開源免費的 Spring Boot 實戰項目:

https://github.com/javastacks/spring-boot-best-practice

現象分析

根據生產環境的報錯日誌來看,這邊屬於Mybatis報出的一個內存溢出情況,通過去看Mybatis源碼發現,底層也是通過一些集合類來存放拼接的sql,那麼當然也有可能出現堆內存溢出,而且在sql體積比較大的情況下,接收sql的集合就會變的非常大,如果回收不了那麼就會導致內存溢出。

由於我們docker容器裏面沒有一些jstack、jmap的工具,並且dump文件也沒有進行保存…導致我無法通過看線程高佔用內存的對象,來分析具體是什麼操作發生的內存溢出,這就難了… 於是只能去網上搜搜看了,沒想到真的給到我一些啓發,並且有點思路大概知道是哪裏的問題。

文章來源於zzzzbw作者寫一篇關於 慘遭DruidDataSource和Mybatis暗算,導致OOM ,很感謝🙏這位作者給我帶來的啓發。 文章作者也遇到了Mybatis帶來的OOM,主要是因爲Mybatis拼接SQL的時候生成的佔位符和參數對象,存放在Map裏,當SQL的參數多導致SQL太長的時候,Map持有這些SQL時間較長,並且多線程同時操作,這時候內存佔用就很高,從而發生OOM

Mybatis源碼分析

通過對DynamicContext類源碼查看,DynamicContext又一個ContextMap 類型的參數bindings,繼承了HashMap相當於一個Map集合,接着看這個類中的getBindings方法,看到了ForEachSqlNode這類調用了getBindings方法,簡單的說就是ForEachSqlNode通過getBindings方法,將SQL參數和參數的佔位符統一put到ContextMap這個集合裏面,主要是這裏面的參數和佔位符無法被GC回收,併發查詢量多的情況下就會導致OOM。

情景復現

隨後我做了線上場景的復現,通過將SQL語句的拼接,將IN裏面的參數變大,然後創建50個線程進行執行,將JVM堆內存設爲-Xmx256m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

這裏看控制檯打印的日誌,服務在頻繁的進行Full GC,導致OOM。

總結

既然發現了問題出現的原因,接下來就是對代碼SQL進行優化,儘量避免在sql拼接的時候體積過大,這裏告誡我們代碼不能亂寫,SQL語句也不能隨意寫啊,有時候把問題想的過於簡單確實會帶來不可預知的風險。

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協程要來了。。。

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這纔是優雅的方式!!

5.《Java開發手冊(嵩山版)》最新發布,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章