現在大部分公司都有自己完整的一套監控系統,比如美團的CAT,我們公司的監控系統也是基於CAT做的二次開發。一般測試環境或生產環境有問題可以直接使用這些系統查看線程和內存運行情況,分析排查問題。
但對於我們開發人員來說還是有必要了解最原始的排查流程,也就是不借助這些系統,使用最基本的命令解決,畢竟了解了這些底層實現對自身發展也是有幫助的。
網上搜下這樣的文章其實很多,比如排查cpu過高,死鎖問題的文章,但大部分講的都是Linux環境下怎么做,其實很多問題在本地開發時就能發現和排查,所以我主要講下 Windows 環境下如何排查,這里舉例講下java應用出現死鎖問題的排查方法。
主要有兩種方式,一種是使用JVM指令+Process Explorer工具,另一種是使用jdk/bin目錄下的jvisualvm.exe工具
一. JVM指令+Process Explorer
常用JVM指令:
jps
主要用來輸出jvm運行的進程狀態jstack
查看某個java進程內的線程堆棧信息
全部命令可參考官方文檔說明
Process Explorer是windows系統的進程管理器,可以查看對應pid(進程id)下的線程信息,方便定位到哪個線程占有的cpu資源高。
排查過程:
1. 打開Process Explorer工具,找到自己的java應用,如果不清楚出問題的java進程是哪個,可以在windows的cmd命令窗口里輸入jps指令查看所有java應用的進程id,如圖:
如果還不能確定哪個pid是你的java應用,可以加上 -lm 參數,
即:jps -lm
,打印出詳細的類名,方便找到對應的pid
還有一種方式是在任務管理器(任務管理器-查看-選擇列-pid)里也能找到對應的pid
2. 根據第一步找到的pid在Process Explorer工具找到那一行記錄然后雙擊打開Thread一欄的tab,就能看的java進程pid對應的線程信息,TID就是對應的線程id,如圖:
3. 在cmd命令行窗口使用jstack
指令把java應用的棧信息dump到本地分析,當然也可以直接在命令行窗口分析,但是一般堆棧信息都比較大,所有的線程信息都在里面,我們只關心出問題線程的堆棧信息,這樣的話的可以使用: jstack pid|findstr tid
這個指令查找我們關心的線程id,但還是建議dump到本地查找,這里的tid要注意一下,jstack
里的線程id是用十六進制表示的,需要把第2步里的tid(十進制)轉為十六進制,如圖:
jstack指令后面的 -l 參數表示輸出鎖信息
- 打開dump文本文件,通過十六進制的tid找到對應的堆棧信息,就可以定位到具體的業務代碼調用位置:
從上圖可以看出出問題的代碼是在DeadLockTest的70行,線程的狀態是BLOCKED,因為dump線程時加上了 -l 的參數(jstack -l pid),所以在dump的最下方jvm會輸出死鎖的信息:
很明顯Thread-1線程在等待0x000000076b940cf0這個鎖,它本身持有0x000000076b940d00這個鎖,而Thread-0剛好在等待0x000000076b940d00這個鎖,它本身持有的鎖是0x000000076b940cf0,這樣成了兩個線程互相等待對方手里持有的鎖,導致了死鎖的出現。
二. jvisualvm.exe工具
這個工具在JDK的安裝目錄的bin文件夾里,打開后也是找到對應的pid,它其實是訪問我們JVM虛擬機里的堆棧信息,優點就是直觀和方便查看線程運行情況,如果有死鎖也會提示出來,如圖: