1. 程式人生 > >如何跟蹤java程式碼的執行

如何跟蹤java程式碼的執行

當我們的java程式在執行時阻塞了,或是執行時越來越慢,我們如何定位程式碼的問題?

在C中可以通過strace來跟蹤程式碼的函式呼叫過程,在除錯程式碼時十分方便。在java中,也有對應的工具。這裡提供2種用來跟蹤java程式碼執行的方法。

jmap

通過該命令捕獲映象,再通過其他命令來檢視。
總的來說是兩步:
(1) 就是通過jmap命令來獲取hprof檔案
(2) 通過工具來檢視該檔案的函式呼叫棧

生成hprof檔案

jmap -dump:file=/tmp/heap.hprof $PID

檢視hprof檔案

檢視hprof檔案可以使用以下工具:MemoryAnalyzer

MemoryAnalyzer的操作步驟

overview -> Leak Suspects -> Table Of Contents -> Thread Overview -> main -> list objects -> with outgoing references

在這個頁面中可以看到類和函式的呼叫過程。
函式是從上到下的呼叫。

jstack

注意: 該命令無法使用使用root來執行。

shell> jstack 7340

這裡的7340是執行zookeeper的程序號。

以下是通過命令jstack觀察zookeeper的輸出得到的類和函式呼叫棧:

... 
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f23ac07f000 nid=0x1d0f in Object.wait() [0x00007f239c3b0000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076f386b40> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait
(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x000000076f386b40> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "main" #1 prio=5 os_prio=0 tid=0x00007f23ac009000 nid=0x1d09 in Object.wait() [0x00007f23b5470000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x000000076fbb90c8> (a org.apache.zookeeper.server.quorum.QuorumPeer) at java.lang.Thread.join(Thread.java:1249) - locked <0x000000076fbb90c8> (a org.apache.zookeeper.server.quorum.QuorumPeer) at java.lang.Thread.join(Thread.java:1323) at org.apache.zookeeper.server.quorum.QuorumPeerMain.runFromConfig(QuorumPeerMain.java:171) at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(QuorumPeerMain.java:114) at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain.java:81) ...

通過以上的輸出,可以清楚的看到zookeeper的執行過程,這對於除錯大型的軟體比如hadoop等,非常方便。