当我们的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等,非常方便。