二、 jstack
此命令是為Java進程或核心文件或遠程調試服務器打印Java線程的堆棧跟蹤。jstack可以同時打印所有線程的Java和本機棧幀。jstack常用于定位線程的死循環(huán)、死鎖等情況。
jstack主要用來查看某個Java進程內的線程堆棧信息。語法格式如下:
jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip
命令行參數(shù)選項說明如下:
-l long listings,會打印出額外的鎖信息,在發(fā)生死鎖時可以用jstack -l pid來觀察鎖持有情況
-m mixed mode,不僅會輸出Java堆棧信息,還會輸出C/C++堆棧信息(比如Native方法)
jstack可以定位到線程堆棧,根據(jù)堆棧信息我們可以定位到具體代碼,所以它在JVM性能調優(yōu)中使用得非常多。下面我們來一個實例找出某個Java進程中最耗費CPU的Java線程并定位堆棧信息,用到的命令有ps、top、printf、jstack、grep。
- 第一步先找出Java進程ID,我部署在服務器上的Java應用名稱為mrf-center:
root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep
root 21711 1 1 14:47 pts/3 00:02:10 java -jar mrf-center.jar
- 得到進程ID為21711,第二步找出該進程內最耗費CPU的線程,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我這里用第三個,輸出如下:

- TIME列就是各個Java線程耗費的CPU時間,CPU時間最長的是線程ID為21742的線程,用
printf "%x\n" 21742
- 得到21742的十六進制值為54ee,下面會用到。
OK,下一步終于輪到jstack上場了,它用來輸出進程21711的堆棧信息,然后根據(jù)線程ID的 十六進制值 grep,如下:
root@ubuntu:/# jstack 21711 | grep 54ee
"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait() [0x00007f94c6eda000]
可以看到CPU消耗在PollIntervalRetrySchedulerThread這個類的Object.wait(),我找了下我的代碼,定位到下面的代碼:

它是輪詢任務的空閑等待代碼,上面的sigLock.wait(timeUntilContinue)就對應了前面的Object.wait()。