1. 程式人生 > >java記憶體佔用異常問題常見排查流程(含堆外記憶體異常)

java記憶體佔用異常問題常見排查流程(含堆外記憶體異常)

開發十年,就只剩下這套架構體系了! >>>   

先初步介紹一下記憶體組成:

java程序佔用記憶體 約等於 Java永久代 + Java堆(新生代和老年代) + 執行緒棧+ Java NIO,其它部分佔用記憶體較小,

詳細可以參考這篇文章  https://my.oschina.net/haitaohu/blog/1830582

第一步:獲取異常程序pid

通過ps 或者 jps獲取 pid

第二步:基本記憶體分配查詢 jmap -heap pid

注意:著重看一下永久區和 老年區 是否夠用,因為前面的都是中轉區域,這兩個是最終落地區域和gc相關

第三步:分析gc是否正常執行

jstat -gccause pid 2000  //每兩秒執行一下

S0 — Heap上的 Survivor space 0 區已使用空間的百分比    
S1 — Heap上的 Survivor space 1 區已使用空間的百分比     
E  — Heap上的 Eden space 區已使用空間的百分比     
O   — Heap上的 Old space 區已使用空間的百分比     
P   — Perm space 區已使用空間的百分比 
YGC — 從應用程式啟動到取樣時發生 Young GC 的次數 
YGCT– 從應用程式啟動到取樣時 Young GC 所用的時間(單位秒)     
FGC — 從應用程式啟動到取樣時發生 Full GC 的次數 
FGCT– 從應用程式啟動到取樣時 Full GC 所用的時間(單位秒)     
GCT — 從應用程式啟動到取樣時用於垃圾回收的總時間(單位秒) 
LGCC - 進行GC的原因(低版本jdk可能沒有這一列)

從這裡觀察gc是否異常,也可以根據這個進行jvm記憶體分配調優,來提高效能降低gc對效能的損耗

如果上面流程還是觀察不出記憶體異常的問題,可能就屬於堆外記憶體問題了,一般出現在io相關操作、 redis、資料庫的連線等

最明顯的特徵:java程序佔用記憶體超過你設定的jvm記憶體最大值

第四步: pmap -x pid 如果需要排序  | sort -n -k3

主要觀察第一列Address和第三列Rss,看哪些記憶體佔用較大,可以在第五步確認

第五部:開啟Native Memory Tracker (NMT)進行排查

在啟動引數上加入-XX:NativeMemoryTracking=detail ,重啟java(tomcat)等

啟動後,通過命令 jcmd 30796 VM.native_memory detail scale=MB >temp.txt 檢視記憶體分配情況

然後根據上圖看哪部分佔用記憶體較高、結合第四步中佔用記憶體高的部分進行搜尋檢視明細,就在這個文件的明細部分

第六步:使用 perf record -g -p 55 開啟監控棧函式呼叫。執行一段時間後Ctrl+C結束,會生成一個檔案perf.data

執行perf report -i perf.data檢視報告

如果這裡還不能定位分析初問題,可以藉助下一步

第七步:對外記憶體排查工具google-perftools ,安裝可以參考 https://my.oschina.net/haitaohu/blog/3024095

注意:多個檔案同時分析

gperftools-2.5/bin/pprof --text /data/jdk1.7.0_65/bin/java /data/java/deploy/google-perftools/local/gzip/gzip.*.heap > tmp.txt1

Analyzing Text Output

Text mode has lines of output that look like this:

       14   2.1%  17.2%       58   8.7% std::_Rb_tree::find  
Here is how to interpret the columns:

1.Number of profiling samples in this function
2.Percentage of profiling samples in this function
3.Percentage of profiling samples in the functions printed so far
4.Number of profiling samples in this function and its callees
5.Percentage of profiling samples in this function and its callees
6.Function name
第一列代表這個函式呼叫本身直接使用了多少記憶體,第二列表示第一列的百分比,第三列是從第一行到當前行的所有第二列之和,第四列表示這個函式呼叫自己直接使用加上所有子呼叫使用的記憶體總和,第五列是第四列的百分比

如果文字分析不夠明顯,也可以匯出pdf檔案

yum -y install ghostscript
yum -y install graphviz 
gperftools-2.5/bin/pprof --pdf /data/jdk1.7.0_65/bin/java /data/java/deploy/google-perftools/local/gzip/gzip.*.heap > tmp.pdf

這樣就很明顯的看到異常點了,無上級節點,通過Unsafe分配使用堆外記憶體,然後去程式碼裡面查一下用到這個的地方

從這七步一般能看出問題來了,這是一次排查後的總結,有些步驟可能是多餘的,但基本這些就能定位分