1. 程式人生 > 實用技巧 >jstack找出最消耗資源的執行緒 並定位程式碼

jstack找出最消耗資源的執行緒 並定位程式碼

Java常用命令(一) jps、jstack、jmap

https://blog.csdn.net/qq_38071004/article/details/81004765 分類專欄:java

一、jps

jps由jdk1.5提供,用於檢視當前使用者下的java程序的pid及基本資訊

1、jps -help

jps的幫助命令,可用jps -h代替:

2、jps -m

檢視程序pid及main方法引數:

圖中 5940 是我的eclipse程序;18648是jps程序,他的main方法引數就是-m;27800是我啟動的hbuilder軟體;47852是我執行的測試函式,引數是zdgHK

3、jps -q

僅顯示pid:

4 、jps -v

檢視pid及JVM引數:

5、 jps -l

檢視pid及程式所在包名:

圖中29852就是我執行的測試Java程式。

二、jstack

使用jstack可檢視指定程序(pid)的堆疊資訊,用以分析執行緒情況:
NEW:未啟動的。不會出現在Dump中。
RUNNABLE:在虛擬機器內執行的。
BLOCKED:受阻塞並等待監視器鎖。
WATING:無限期等待另一個執行緒執行特定操作。
TIMED_WATING:有時限的等待另一個執行緒的特定操作。
TERMINATED:已退出的。

1、jstack -h

幫助命令:

2、jstack [-l][-m][-F] pid

-l

:長列表,列印鎖的附加資訊;
-m:列印java和native c/c++框架的所有棧資訊;
-F:沒有響應的時候強制列印棧資訊;

3、例

首先通過jps檢視程序pid:

然後通過jstack 55872 列印堆疊資訊:

圖中僅是一部分資訊截圖,可以看到當前主執行緒狀態是TIMED_WATING,在程式第6行:

4、執行緒死鎖檢視:

程式:

public class JpsTest {
    public static void main(String[] args) throws InterruptedException {
        //建立資源
        final Object a = new Object();
        final Object b = new Object();
        //啟動執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                //獲取a的鎖
                synchronized (a) {
                    try {
                        System.out.println("i'm t1");
                        //等待一會兒,確保下一個執行緒獲得另一個資源物件鎖
                        Thread.sleep(100);
                        //獲取b的鎖
                        synchronized (b) {
                            System.out.println("t1------");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        //啟動執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                //獲取b的鎖
                synchronized (b) {
                    try {
                        System.out.println("i'm t2");
                        //等待一會兒,確保下一個執行緒獲得另一個資源物件鎖
                        Thread.sleep(100);
                        //獲取a的鎖
                        synchronized (a) {
                            System.out.println("t2------");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

程式中兩個執行緒分別持有對方所需資源的鎖並等待對方釋放導致死鎖。
檢視jstack列印資訊:

可以看到圖中第一行顯示發現了執行緒死鎖,Thread-1等待資源- waiting to lock <0x00000000eb4c0bf8> (a java.lang.Object),且鎖住了資源- locked <0x00000000eb4c0c08> (a java.lang.Object),Thread2則與之相反。

3、jmap與jhat

檢視堆記憶體使用情況:
jmap -heap pid:通過可檢視堆記憶體的配置情況及使用情況
jmap -histo pid:統計物件的建立數量
jmap -dump:format=b,file=heapDump pid:生成dump檔案與jhat配合使用
jhat -port xxxx heapDump:瀏覽器訪問localhost:xxxx即可檢視dump
例:
程式(程式簡陋,忽略細節):

public class JmapTest {
    public static void main(String[] args) throws InterruptedException {
        JmapTest test = new JmapTest(300);
        fun(test);
        System.out.println(test.a);
    }

    private JmapTest next;
    private Integer a;
    public JmapTest(int a) {
        this.a = a;
    }
    //通過向一個連結串列遞迴新增物件
    public static void fun(JmapTest m) throws InterruptedException {
        System.out.println(m.a);
        m.next = new JmapTest(++m.a);
        //避免過早傳送記憶體溢位
        Thread.sleep(1000);
        fun(m.next);
    }
}

首先通過使用jps -l獲得pid,再通過jmap -heap pid檢視堆記憶體配置及使用情況:
配置資訊:

使用情況:

接下來通過jmap -histo pid檢視物件建立數量:

圖中我們得程式已經建立了401個例項物件了。
通過jmap -dump:format=b,file=heapDump pid生成heapDump檔案:

這樣檔案已經建立成功,再通過jhat -port xxxx heapDump 啟動一個監聽程式檢視檔案:

程式已經啟動,接下來在瀏覽器檢視:

_______________________________________________________________________

jstack找出最消耗資源的執行緒 並定位程式碼

jstack可以定位到執行緒堆疊,根據堆疊資訊我們可以定位到具體程式碼,所以它在JVM效能調優中使用得非常多。下面我們來一個例項找出某個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的執行緒,可以使用
1)ps -Lfp pid
2)ps -mp pid -o THREAD, tid, time
3)top -Hp pid
用第三個,輸出如下:

TIME列就是各個Java執行緒耗費的CPU時間,CPU時間最長的是執行緒ID為21742的執行緒,用

printf "%x\n" 21742

得到21742的十六進位制值為54ee,下面會用到。

OK,下一步終於輪到jstack上場了,它用來輸出程序21711的堆疊資訊,然後根據執行緒ID的十六進位制值grep,如下:

root@ubuntu:/# jstack 21711 | grep 54ee
"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait()

可以看到CPU消耗在PollIntervalRetrySchedulerThread這個類的Object.wait(),我找了下我的程式碼,定位到下面的程式碼:

// Idle wait
getLog().info("Thread [" + getName() + "] is idle waiting...");
schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;
long now = System.currentTimeMillis();
long waitTime = now + getIdleWaitTime();
long timeUntilContinue = waitTime - now;
synchronized(sigLock) {
  try {
    if(!halted.get()) {
      sigLock.wait(timeUntilContinue);
    }
  } 
  catch (InterruptedException ignore) {
  }
}

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

_____________________________________________________________________________________________________________________

jps 、jstack命令詳解

一、jps命令shi yong

jps是jdk提供的一個檢視當前java程序的小工具, 可以看做是JavaVirtual Machine Process Status Tool的縮寫。非常簡單實用。

命令格式:jps [options ] [ hostid ]

[options]選項:
-q:僅輸出VM識別符號,不包括classname,jar name,arguments in main method
-m:輸出main method的引數
-l:輸出完全的包名,應用主類名,jar的完全路徑名
-v:輸出jvm引數
-V:輸出通過flag檔案傳遞到JVM中的引數(.hotspotrc檔案或-XX:Flags=所指定的檔案
-Joption:傳遞引數到vm,例如:-J-Xms512m

[hostid]:

[protocol:][[//]hostname][:port][/servername]

命令的輸出格式 :
lvmid [ [ classname| JARfilename | "Unknown"] [ arg* ] [ jvmarg* ] ]

1)jps

2)jps –l:輸出主類或者jar的完全路徑名

3)jps –v :輸出jvm引數

4)jps –q :僅僅顯示Java程序號

二、jstack

jstack用於打印出給定的java程序ID或corefile或遠端除錯服務的Java堆疊資訊,如果是在64位機器上,需要指定選項"-J-d64",Windows的jstack使用方式只支援以下的這種方式:

jstack[-l]pid

如果java程式崩潰生成core檔案,jstack工具可以用來獲得core檔案的javastack和nativestack的資訊,從而可以輕鬆地知道java程式是如何崩潰和在程式何處發生問題。另外,jstack工具還可以附屬到正在執行的java程式中,看到當時執行的java程式的javastack和nativestack的資訊,如果現在執行的java程式呈現hung的狀態,jstack是非常有用的。

2、命令格式
jstack[option]pid
jstack[option]executablecore
jstack[option][server-id@]remote-hostname-or-IP

3、常用引數說明

1)、options:

executableJavaexecutablefromwhichthecoredumpwasproduced.

(可能是產生coredump的java可執行程式)

core將被列印資訊的coredump檔案

remote-hostname-or-IP遠端debug服務的主機名或ip

server-id唯一id,假如一臺主機上多個遠端debug服務

2)、基本引數:

-F當’jstack[-l]pid’沒有相應的時候強制列印棧資訊

-l長列表.列印關於鎖的附加資訊,例如屬於java.util.concurrent的ownablesynchronizers列表.

-m列印java和nativec/c++框架的所有棧資訊.

-h|-help列印幫助資訊

pid需要被列印配置資訊的java程序id,可以用jps查詢.

4、使用示例