怎的使用jstack診斷Java應用程序故障

http://www.myexception.cn/javascript/1030478.html


怎樣使用jstack診斷Java應用程序故障
       最近一段時間,我們的生產系統升級頻繁出現故障,具體故障現象是啓動後10來分鐘就出現交易緩慢,處理線程耗盡等現象,並且故障發生的頻率蠻高的。經過詳細的診斷和排查,終於發現了問題,是groovy在osgi中運行會出現classloader死鎖,最後我們也解決了這個問題。
       如果單靠通過查看代碼是很難去發現這個問題,在這一次故障排查中,我也學到了怎樣更好的使用jvm監控工具來進行診斷,主要用到了jstack和jmap命令,jmap上次已經講過就不再講了,下面就一個例子來講怎麼使用jstack來對的Java程序進行診斷。
       首先讓我們來了解一下jstack這個命令的作用,jstack 是一個可以返回在應用程序上運行的各種各樣線程的一個完整轉儲的實用程序,您可以使用它查明問題。jstack [-l] <pid>,jpid可以通過使用jps命令來查看當前Java程序的jpid值,-l是可選參數,它可以顯示線程阻塞/死鎖情況。

/**
 * 死鎖例子
 * @author crane.ding
 * @since 2011-3-20
 */
public class DeadLock {

	public static void main(String[] args) {
		final Object obj_1 = new Object(), obj_2 = new Object();
		
		Thread t1 = new Thread("t1"){
			@Override
			public void run() {
				synchronized (obj_1) {
					try {
						Thread.sleep(3000);
					} catch (InterruptedException e) {}
					
					synchronized (obj_2) {
						System.out.println("thread t1 done.");
					}
				}
			}
		};
		
		Thread t2 = new Thread("t2"){
			@Override
			public void run() {
				synchronized (obj_2) {
					try {
						Thread.sleep(3000);
					} catch (InterruptedException e) {}
					
					synchronized (obj_1) {
						System.out.println("thread t2 done.");
					}
				}
			}
		};
		
		t1.start();
		t2.start();
	}
	
}

       以上DeadLock類是一個死鎖的例子,假使在我們不知情的情況下,運行DeadLock後,發現等了N久都沒有在屏幕打印線程完成信息。這個時候我們就可以使用jps查看該程序的jpid值和使用jstack來生產堆棧結果問題。
$ java -cp deadlock.jar DeadLock &
$ 

$ jps
  3076 Jps
  448 DeadLock
$ jstack -l 448 > deadlock.jstack

結果文件deadlock.jstack內容如下:
2011-03-20 23:05:20
Full thread dump Java HotSpot(TM) Client VM (19.1-b02 mixed mode, sharing):

"DestroyJavaVM" prio=6 tid=0x00316800 nid=0x9fc waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"t2" prio=6 tid=0x02bcf000 nid=0xc70 waiting for monitor entry [0x02f6f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.demo.DeadLock$2.run(DeadLock.java:40)
	- waiting to lock <0x22a297a8> (a java.lang.Object)
	- locked <0x22a297b0> (a java.lang.Object)

   Locked ownable synchronizers:
	- None

"t1" prio=6 tid=0x02bce400 nid=0xba0 waiting for monitor entry [0x02f1f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.demo.DeadLock$1.run(DeadLock.java:25)
	- waiting to lock <0x22a297b0> (a java.lang.Object)
	- locked <0x22a297a8> (a java.lang.Object)

   Locked ownable synchronizers:
	- None

"Low Memory Detector" daemon prio=6 tid=0x02bb9400 nid=0xa6c runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"CompilerThread0" daemon prio=10 tid=0x02bb2800 nid=0xcb8 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Attach Listener" daemon prio=10 tid=0x02bb1000 nid=0x7f4 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Signal Dispatcher" daemon prio=10 tid=0x02bd2800 nid=0xd80 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Finalizer" daemon prio=8 tid=0x02bab000 nid=0xe1c in Object.wait() [0x02d3f000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x229e1148> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
	- locked <0x229e1148> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

   Locked ownable synchronizers:
	- None

"Reference Handler" daemon prio=10 tid=0x02ba6800 nid=0xbe0 in Object.wait() [0x02cef000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x229e1048> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:485)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
	- locked <0x229e1048> (a java.lang.ref.Reference$Lock)

   Locked ownable synchronizers:
	- None
"VM Thread" prio=10 tid=0x02b6a400 nid=0x568 runnable 

"VM Periodic Task Thread" prio=10 tid=0x02bc8400 nid=0x75c waiting on condition 

JNI global references: 878


Found one Java-level deadlock:
=============================
"t2":
  waiting to lock monitor 0x02baaeec (object 0x22a297a8, a java.lang.Object),
  which is held by "t1"
"t1":
  waiting to lock monitor 0x02baa2bc (object 0x22a297b0, a java.lang.Object),
  which is held by "t2"

Java stack information for the threads listed above:
===================================================
"t2":
	at com.demo.DeadLock$2.run(DeadLock.java:40)
	- waiting to lock <0x22a297a8> (a java.lang.Object)
	- locked <0x22a297b0> (a java.lang.Object)
"t1":
	at com.demo.DeadLock$1.run(DeadLock.java:25)
	- waiting to lock <0x22a297b0> (a java.lang.Object)
	- locked <0x22a297a8> (a java.lang.Object)

Found 1 deadlock.

       從這個結果文件我們一看到發現了一個死鎖,具體是線程t2在等待線程t1,而線程t1在等待線程t2造成的,同時也記錄了線程的堆棧和代碼行數,通過這個堆棧和行數我們就可以去檢查對應的代碼塊,從而發現問題和解決問題。
1 樓 sdh5724 2011-03-21  
$JAVA_HOME/bin 下的幾個工具都值得學習使用:
jps
jstat
jstack
jinfo
jmap
.....

這是無工具環境的最後的手段, 可以好好學學使用。 我基本用這些能解決99%的問題哦。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章