1. 程式人生 > >生產服務記憶體洩漏分析過程

生產服務記憶體洩漏分析過程

最近生產遇到記憶體洩漏的問題,說一下排查過程及內心歷程。

生產報錯:java.lang.OutOfMemoryError: Java heap space

堆記憶體洩漏一般有以下情況:

1,  堆記憶體本身沒有設定或者配置引數設定不合適,若按預設啟動,預設是256m?512m?,而服務本身複雜,不夠用

2,  堆中物件死了,但是GC無法回收空間,記憶體洩漏

3,  服務有大物件,當有過大物件時,而此時堆空間不足,記憶體溢位、

還有其他情況,上面三種情況都會導致java.lang.OutOfMemoryError錯誤。

所以針對上述情況排查過程如下:剛開始只是通過簡單的jmap,jstat,jstack等命令分別查看了當時服務的堆記憶體狀況,YGC,FGC次數及耗時時間,當時堆疊的情況等,看完之後,沒有任何頭緒,所以轉換思路重新生成dump檔案,執行如下命令:

jmap -dump:format=b,file=jconsole.dump pid

生產的dump檔案用專門的工具memory analyzer分析。

分析思路如下:

匯入檔案後,介面如下:

1,Actions------>Histogram

先檢視當前 Actions 下Histogram 檢視當前每個類有多少例項如下:

 

                                                                 圖一

通過正則匹配,檢視xxx服務類所佔空間。

圖略,分析原因不在這。

2,Reports----> LeakSuspects

Leak Suspects: includes leak suspects and asystem overview 記憶體洩漏和系統概況

點開 Leak Suspects 如圖:

看到已經自動分析好的2個最可能的記憶體洩漏的問題,

問題1:

點開Details

找到

再找到

找到並開啟所佔數值大的物件

裡面載入的是mybatis對映檔案,正常,再找佔用大記憶體的


一個是sql語句,一個是結果集

再分析sql語句,找出其中幾個

body 是SQL語句

body是見截圖

是各種組裝的sql語句及查詢條件;

繼續往下看,找到

看一下用堆記憶體比較大的物件,進去檢視

其中一個,是資料庫的某個欄位

此問題的原因就是操作資料庫,根據sql找到相關的程式碼,分析一下原因。

問題2:

類載入器載入物件佔14.78%,分析如下:

找最大的物件 class,開啟如下:


只列出25個,還有9797

個,這大概可以說明1,服務依賴的類包多,但是微服務不應該有如此大的jar包依賴;

2,依賴的其他服務所依賴的包也載入進來,這就是多餘的包,應該去掉多餘的類包,減輕類載入器載入的jar包

分析建議:

分析服務所依賴的jar包,去掉多餘的jar包,減少不必要的類載入。

至此,兩個最可能記憶體洩漏的點已經找到。繼續驗證剛才的問題。

3,  Reports-----> Top Components

Top Components: list reports for componentsbigger than 1 percent of the total heap.

列出報告中總記憶體佔用大於1%的部分。

開啟第一個:

開啟:Possible Memory Waste 可能的記憶體垃圾


開啟Details

由於String型別底層儲存的就是字元陣列,主要排查物件就是字串,如下:

找到批量插入組裝的sql語句,

 驗證了問題一的分析。

再看空間垃圾回收率很低,如下:翻譯一下就是垃圾回收率低於20%的記憶體塊

發現這些是儲存類的反射及基本資訊儲存的

 

發現ibatis的sessionfactory佔用了將近50%的堆空間,還是說明sql有問題,見上面分析出來的sql原因,再查程式碼。

再看軟引用,這也會導致記憶體洩漏,如下:

開啟Details,簡單舉例一個如下:

再結合程式碼分析,推測此類該方法發生了多個方法同時呼叫的問題,請避免此類問題,減少軟引用,縮短垃圾回收時間。

再看Histogram of Softly Referenced:

看到有3300個軟引用:

經過GC,仍然有581個存活:

 

檢視原因:

前10個如下:

都是一些常量引用,如果這些常量沒有必要,就別再載入了。

問題分析總結:

綜上分析,建議如下:

1,  sql問題,分析dump檔案發現有大量查詢語句,大量批量插入資料庫,如xxxxx查詢,需要結合程式碼檢視是否有限制條件,或者是否一次性查出資料太多等;

xxxxxx

等批量插入,是否涉及到插入資料量很大等等,結合程式碼分析,是否有繼續優化的空間。

2,  類包問題,仔細分析一下xxx服務,到底都有哪些jar包需要依賴,把不需要依賴的排除掉,這樣可以減少多餘類對堆的佔用,提供堆的利用空間和減少GC。