前言
之前線上有過一兩次OOM的問題,但是每次定位問題都有點手足無措的感覺,剛好利用星期天,以測試環(huán)境為模版來學習一下Linux常用的幾個排查問題的命令。?
也可以幫助自己在以后的工作中快速的排查線上問題。
jmap命令
jmap -heap pid 輸出當前進程 JVM 堆新生代、老年代、持久代等請情況,GC 使用的算法等信息?
jmap -histo:live {pid} | head -n 10 輸出當前進程內存中所有對象包含的大小??
jmap -dump:format=b,file=/usr/local/logs/gc/dump.hprof {pid} 以二進制輸出檔當前內存的堆情況,然后可以導入 MAT 等工具進行
1、 jmap -heap pid
輸出當前進程JVM堆新生代、老年代、持久代等情況,GC使用的算法等信息。?

2、jmap -histo:live {pid} | head -n 10 輸出當前進程內存中所有對象包含的大小
輸出當前進程內存中所有對象實例數(shù) (instances) 和大小 (bytes), 如果某個業(yè)務對象實例數(shù)和大小存在異常情況,可能存在內存泄露或者業(yè)務設計方面存在不合理之處。?

jmap -dump:
命令如下:?
mkdir logs?
jmap -dump:format=b,file=/tmp/logs/dump.hprof {pid}
-dump:formate=b,file= 以二進制輸出當前內存的堆情況至相應的文件,然后可以結合 MAT 等內存分析工具深入分析當前內存情況。?
也可以通過JVM參數(shù)配置OOM時自動dump當前內存鏡像文件。 -XX:+HeapDumpOnOutOfMemoryError 和-XX:HeapDumpPath所代表的含義就是當程序出現(xiàn)OutofMemory時,將會在相應的目錄下生成一份dump文件,而如果不指定選項-XX:HeapDumpPath則在當前目錄下生成dump文件。?
確保應用發(fā)生 OOM 時 JVM 能夠保存并 dump 出當前的內存鏡像。?
當然,如果你決定手動 dump 內存時,dump 操作占據(jù)一定 CPU 時間片、內存資源、磁盤資源等,因此會帶來一定的負面影響。?
此外,dump 的文件可能比較大 , 一般我們可以考慮使用 zip 命令對文件進行壓縮處理,這樣在下載文件時能減少帶寬的開銷。?
下載 dump 文件完成之后,由于 dump 文件較大可將 dump 文件備份至制定位置或者直接刪除,以釋放磁盤在這塊的空間占用。
dump 日志分析
MAT(Memory Analyzer Tool),一個基于 Eclipse 的內存分析工具,是一個快速、功能豐富的 JAVA heap 分析工具,它可以幫助我們查找內存泄漏和減少內存消耗。?
使用內存分析工具從眾多的對象中進行分析,快速的計算出在內存中對象的占用大小,看看是誰阻止了垃圾收集器的回收工作,并可以通過報表直觀的查看到可能造成這種結果的對象。?
具體可以參考:Java內存分析工具MAT(Memory Analyzer Tool)安裝使用實例 : https://blog.csdn.net/jin_kwok/article/details/80326088?和?基于Java內存dump文件分析解決內存泄漏問題 : http://www.itdecent.cn/p/2cf7169ba1c4
jstack命令
printf '%x\n' tid --> 10 進制至 16 進制線程 ID(navtive 線程) %d 10 進制?
jstack pid | grep tid -C 30 --color ps -mp 8278 -o THREAD,tid,time | head -n 40
某 Java 進程 CPU 占用率高,我們想要定位到其中 CPU 占用率最高的線程。?
(1) 先利用top命令找到CPU占用高的進程pid?
也可以通過ps -ef | grep 應用名 來快速定位自己應用的pid?

顯示pid:29080?
(2) 利用 top 命令可以查出占 CPU 最高的線程 pid (先找到該pid 29080下所有的線程數(shù)據(jù))?

可以看到占用cpu資源最高的為29173
(3) 占用率最高的線程 ID 為29173,將其轉換為 16 進制形式 (因為 java native 線程以 16 進制形式輸出)
printf '%x\n' 29173?

(4) 利用 jstack 打印出 java 線程調用棧信息?
jstack 29080 | grep '0x71f5' -A 50 --color?

可以看到這個線程是在做kafka相關的操作。因為這是測試,所以并不是因為CPU真的占用過高的情況。?
更多內容也可以參考:?
如何使用jstack分析線程狀態(tài) : http://www.itdecent.cn/p/6690f7e92f27?
通過jstack與jmap分析一次線上故障: https://www.cnblogs.com/kingszelda/p/9034191.html
jinfo命令
jinfo可以用來查看正在運行的java運用程序的擴展參數(shù)。?
查看pid對應的JVM參數(shù),可以到?PerfMa : http://xxfox.perfma.com/jvm/check?校驗參數(shù)的正確性?
jinfo -flags pid?

拿到Command line后面的配置參數(shù)到perfma中驗證查詢:?

這里面好多功能可以去使用。
jstat命令
jstat:Java Virtual Machine statistics monitoring tool JDK自帶的一個輕量級小工具。
jstat顯示GC執(zhí)行的情況
jstat -gc 12538 5000?
即會每5秒一次顯示進程號為12538的java進成的GC情況

說明:?
S0C、S1C、S0U、S1U:Survivor 0/1區(qū)容量(Capacity)和使用量(Used)?
EC、EU:Eden區(qū)容量和使用量?
OC、OU:年老代容量和使用量?
PC、PU:永久代容量和使用量?
YGC、YGT:年輕代GC次數(shù)和GC耗時?
FGC、FGCT:Full GC次數(shù)和Full GC耗時?
GCT:GC總耗時
顯示內容說明如下(部分結果是通過其他其他參數(shù)顯示的,暫不說明):?
S0C:年輕代中第一個survivor(幸存區(qū))的容量 (字節(jié))?
S1C:年輕代中第二個survivor(幸存區(qū))的容量 (字節(jié))?
S0U:年輕代中第一個survivor(幸存區(qū))目前已使用空間 (字節(jié))?
S1U:年輕代中第二個survivor(幸存區(qū))目前已使用空間 (字節(jié))?
EC:年輕代中Eden(伊甸園)的容量 (字節(jié))?
EU:年輕代中Eden(伊甸園)目前已使用空間 (字節(jié))?
OC:Old代的容量 (字節(jié))?
OU:Old代目前已使用空間 (字節(jié))?
PC:Perm(持久代)的容量 (字節(jié))?
PU:Perm(持久代)目前已使用空間 (字節(jié))?
YGC:從應用程序啟動到采樣時年輕代中gc次數(shù)?
YGCT:從應用程序啟動到采樣時年輕代中gc所用時間(s)?
FGC:從應用程序啟動到采樣時old代(全gc)gc次數(shù)?
FGCT:從應用程序啟動到采樣時old代(全gc)gc所用時間(s)?
GCT:從應用程序啟動到采樣時gc用的總時間(s)?
總結
一般分析CPU或者內存異常情況可以通過以下幾步:
查看日志
查看CPU情況
查看TCP情況
查看java線程,jstack
查看java堆,jmap
通過MAT分析堆文件,尋找無法被回收的對象
參考:?
Java線上問題排查思路與工具使用 : https://blog.csdn.net/GitChat/article/details/79019454