這篇文章主要為大家展示了“Java線程Dump分析工具jstack怎么用”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Java線程Dump分析工具jstack怎么用”這篇文章吧。
堅(jiān)守“ 做人真誠(chéng) · 做事靠譜 · 口碑至上 · 高效敬業(yè) ”的價(jià)值觀,專(zhuān)業(yè)網(wǎng)站建設(shè)服務(wù)10余年為成都廣告制作小微創(chuàng)業(yè)公司專(zhuān)業(yè)提供企業(yè)網(wǎng)站制作營(yíng)銷(xiāo)網(wǎng)站建設(shè)商城網(wǎng)站建設(shè)手機(jī)網(wǎng)站建設(shè)小程序網(wǎng)站建設(shè)網(wǎng)站改版,從內(nèi)容策劃、視覺(jué)設(shè)計(jì)、底層架構(gòu)、網(wǎng)頁(yè)布局、功能開(kāi)發(fā)迭代于一體的高端網(wǎng)站建設(shè)服務(wù)。
jstack用于打印出給定的java進(jìn)程ID或core file或遠(yuǎn)程調(diào)試服務(wù)的Java堆棧信息,如果是在64位機(jī)器上,需要指定選項(xiàng)"-J-d64",Windows的jstack使用方式只支持以下的這種方式:
jstack [-l][F] pid
如果java程序崩潰生成core文件,jstack工具可以用來(lái)獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發(fā)生問(wèn)題。另外,jstack工具還可以附屬到正在運(yùn)行的java程序中,看到當(dāng)時(shí)運(yùn)行的java程序的java stack和native stack的信息, 如果現(xiàn)在運(yùn)行的java程序呈現(xiàn)hung的狀態(tài),jstack是非常有用的。進(jìn)程處于hung死狀態(tài)可以用-F強(qiáng)制打出stack。
dump 文件里,值得關(guān)注的線程狀態(tài)有:
死鎖,Deadlock(重點(diǎn)關(guān)注)
執(zhí)行中,Runnable
等待資源,Waiting on condition(重點(diǎn)關(guān)注)
等待獲取監(jiān)視器,Waiting on monitor entry(重點(diǎn)關(guān)注)
暫停,Suspended
對(duì)象等待中,Object.wait() 或 TIMED_WAITING
阻塞,Blocked(重點(diǎn)關(guān)注)
停止,Parked
在摘了另一篇博客的三種場(chǎng)景:
實(shí)例一:Waiting to lock 和 Blocked
"RMI TCP Connection(267865)-172.16.5.25" daemon prio=10 tid=0x00007fd508371000 nid=0x55ae waiting for monitor entry [0x00007fd4f8684000] java.lang.Thread.State: BLOCKED (on object monitor) at org.apache.log4j.Category.callAppenders(Category.java:201) - waiting to lock <0x00000000acf4d0c0> (a org.apache.log4j.Logger) at org.apache.log4j.Category.forcedLog(Category.java:388) at org.apache.log4j.Category.log(Category.java:853) at org.apache.commons.logging.impl.Log4JLogger.warn(Log4JLogger.java:234) at com.tuan.core.common.lang.cache.remote.SpyMemcachedClient.get(SpyMemcachedClient.java:110)
說(shuō)明:
1)線程狀態(tài)是 Blocked,阻塞狀態(tài)。說(shuō)明線程等待資源超時(shí)!
2)“ waiting to lock <0x00000000acf4d0c0>”指,線程在等待給這個(gè) 0x00000000acf4d0c0 地址上鎖(英文可描述為:trying to obtain 0x00000000acf4d0c0 lock)。
3)在 dump 日志里查找字符串 0x00000000acf4d0c0,發(fā)現(xiàn)有大量線程都在等待給這個(gè)地址上鎖。如果能在日志里找到誰(shuí)獲得了這個(gè)鎖(如locked < 0x00000000acf4d0c0 >),就可以順藤摸瓜了。
4)“waiting for monitor entry”說(shuō)明此線程通過(guò) synchronized(obj) {……} 申請(qǐng)進(jìn)入了臨界區(qū),從而進(jìn)入了下圖1中的“Entry Set”隊(duì)列,但該 obj 對(duì)應(yīng)的 monitor 被其他線程擁有,所以本線程在 Entry Set 隊(duì)列中等待。
5)第一行里,"RMI TCP Connection(267865)-172.16.5.25"是 Thread Name 。tid指Java Thread id。nid指native線程的id。prio是線程優(yōu)先級(jí)。[0x00007fd4f8684000]是線程棧起始地址。
實(shí)例二:Waiting on condition 和 TIMED_WAITING
"RMI TCP Connection(idle)" daemon prio=10 tid=0x00007fd50834e800 nid=0x56b2 waiting on condition [0x00007fd4f1a59000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000000acd84de8> (a java.util.concurrent.SynchronousQueue$TransferStack) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198) at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424) at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323) at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907) at java.lang.Thread.run(Thread.java:662)
說(shuō)明:
1)“TIMED_WAITING (parking)”中的 timed_waiting 指等待狀態(tài),但這里指定了時(shí)間,到達(dá)指定的時(shí)間后自動(dòng)退出等待狀態(tài);parking指線程處于掛起中。
2)“waiting on condition”需要與堆棧中的“parking to wait for <0x00000000acd84de8> (a java.util.concurrent.SynchronousQueue$TransferStack)”結(jié)合來(lái)看。首先,本線程肯定是在等待某個(gè)條件的發(fā)生,來(lái)把自己?jiǎn)拘?。其次,SynchronousQueue 并不是一個(gè)隊(duì)列,只是線程之間移交信息的機(jī)制,當(dāng)我們把一個(gè)元素放入到 SynchronousQueue 中時(shí)必須有另一個(gè)線程正在等待接受移交的任務(wù),因此這就是本線程在等待的條件。
3)別的就看不出來(lái)了。
實(shí)例三:in Obejct.wait() 和 TIMED_WAITING
"RMI RenewClean-[172.16.5.19:28475]" daemon prio=10 tid=0x0000000041428800 nid=0xb09 in Object.wait() [0x00007f34f4bd0000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000aa672478> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) - locked <0x00000000aa672478> (a java.lang.ref.ReferenceQueue$Lock) at sun.rmi.transport.DGCClient$EndpointEntry$RenewCleanThread.run(DGCClient.java:516) at java.lang.Thread.run(Thread.java:662)
說(shuō)明:
1)“TIMED_WAITING (on object monitor)”,對(duì)于本例而言,是因?yàn)楸揪€程調(diào)用了 java.lang.Object.wait(long timeout) 而進(jìn)入等待狀態(tài)。
2)“Wait Set”中等待的線程狀態(tài)就是“ in Object.wait() ”。當(dāng)線程獲得了 Monitor,進(jìn)入了臨界區(qū)之后,如果發(fā)現(xiàn)線程繼續(xù)運(yùn)行的條件沒(méi)有滿足,它則調(diào)用對(duì)象(一般就是被 synchronized 的對(duì)象)的 wait() 方法,放棄了 Monitor,進(jìn)入 “Wait Set”隊(duì)列。只有當(dāng)別的線程在該對(duì)象上調(diào)用了 notify() 或者 notifyAll() ,“ Wait Set”隊(duì)列中線程才得到機(jī)會(huì)去競(jìng)爭(zhēng),但是只有一個(gè)線程獲得對(duì)象的 Monitor,恢復(fù)到運(yùn)行態(tài)。
3)RMI RenewClean 是 DGCClient 的一部分。DGC 指的是 Distributed GC,即分布式垃圾回收。
4)請(qǐng)注意,是先 locked <0x00000000aa672478>,后 waiting on <0x00000000aa672478>,之所以先鎖再等同一個(gè)對(duì)象,請(qǐng)看下面它的代碼實(shí)現(xiàn):
static private class Lock { }; private Lock lock = new Lock(); public Reference extends T> remove(long timeout) { synchronized (lock) { Reference extends T> r = reallyPoll(); if (r != null) return r; for (;;) { lock.wait(timeout); r = reallyPoll(); …… } }
即,線程的執(zhí)行中,先用 synchronized 獲得了這個(gè)對(duì)象的 Monitor(對(duì)應(yīng)于 locked <0x00000000aa672478> );當(dāng)執(zhí)行到 lock.wait(timeout);,線程就放棄了 Monitor 的所有權(quán),進(jìn)入“Wait Set”隊(duì)列(對(duì)應(yīng)于 waiting on <0x00000000aa672478> )。
5)從堆棧信息看,是正在清理 remote references to remote objects ,引用的租約到了,分布式垃圾回收在逐一清理呢。
referance:
通過(guò)jstack分析解決進(jìn)程死鎖問(wèn)題
以上是“Java線程Dump分析工具jstack怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!