亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

java(優化23) jstack和線程dump分析

2019-11-06 06:07:19
字體:
來源:轉載
供稿:網友

一:jstack

jstack命令的語法格式: jstack <pid>??梢杂胘ps查看java進程id。這里要注意的是:1. 不同的 JAVA虛機的線程 DUMP的創建方法和文件格式是不一樣的,不同的 JVM版本, dump信息也有差別。本文中,只以 SUN的 hotspot JVM 5.0_06 為例。2. 在實際運行中,往往一次 dump的信息,還不足以確認問題。建議產生三次 dump信息,如果每次 dump都指向同一個問題,我們才確定問題的典型性。

二:線程分析 2.1. JVM 線程 在線程中,有一些 JVM內部的后臺線程,來執行譬如垃圾回收,或者低內存的檢測等等任務,這些線程往往在 JVM初始化的時候就存在,如下所示:

"Low Memory Detector" daemon PRio=10 tid=0x081465f8 nid=0x7 runnable [0x00000000..0x00000000]          "CompilerThread0" daemon prio=10 tid=0x08143c58 nid=0x6 waiting on condition [0x00000000..0xfb5fd798]          "Signal Dispatcher" daemon prio=10 tid=0x08142f08 nid=0x5 waiting on condition [0x00000000..0x00000000]          "Finalizer" daemon prio=10 tid=0x08137ca0 nid=0x4 in Object.wait() [0xfbeed000..0xfbeeddb8]          at java.lang.Object.wait(Native Method)          - waiting on <0xef600848> (a java.lang.ref.ReferenceQueue$Lock)          at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)          - locked <0xef600848> (a java.lang.ref.ReferenceQueue$Lock)         at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)          at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)          "Reference Handler" daemon prio=10 tid=0x081370f0 nid=0x3 in Object.wait() [0xfbf4a000..0xfbf4aa38]            at java.lang.Object.wait(Native Method)          - waiting on <0xef600758> (a java.lang.ref.Reference$Lock)          at java.lang.Object.wait(Object.java:474)          at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)          - locked <0xef600758> (a java.lang.ref.Reference$Lock)          "VM Thread" prio=10 tid=0x08134878 nid=0x2 runnable          "VM Periodic Task Thread" prio=10 tid=0x08147768 nid=0x8 waiting on condition 我們更多的是要觀察用戶級別的線程,如下所示:
"Thread-1" prio=10 tid=0x08223860 nid=0xa waiting on condition [0xef47a000..0xef47ac38]          at java.lang.Thread.sleep(Native Method)          at testthread.MySleepingThread.method2(MySleepingThread.java:53)          - locked <0xef63d600> (a testthread.MySleepingThread)        at testthread.MySleepingThread.run(MySleepingThread.java:35)        at java.lang.Thread.run(Thread.java:595) 我們能看到:    * 線程的狀態: waiting on condition    * 線程的調用棧    * 線程的當前鎖住的資源: <0xef63d600> 

2.2. 線程的狀態分析        正如我們剛看到的那樣,線程的狀態是一個重要的指標,它會顯示在線程 Stacktrace的頭一行結尾的地方。那么線程常見的有哪些狀態呢?線程在什么樣的情況下會進入這種狀態呢?我們能從中發現什么線索?< /span>1.1 Runnable 該狀態表示線程具備所有運行條件,在運行隊列中準備操作系統的調度,或者正在運行。1.2 Wait on condition        該狀態出現在線程等待某個條件的發生。具體是什么原因,可以結合 stacktrace來分析。最常見的情況是線程在等待網絡的讀寫,比如當網絡數據沒有準備好讀時,線程處于這種等待狀態,而一旦有數據準備好讀之后,線程會重新激活,讀取并處理數據。在 Java引入 NewIO之前,對于每個網絡連接,都有一個對應的線程來處理網絡的讀寫操作,即使沒有可讀寫的數據,線程仍然阻塞在讀寫操作上,這樣有可能造成資源浪費,而且給操作系統的線程調度也帶來壓力。在 NewIO里采用了新的機制,編寫的服務器程序的性能和可擴展性都得到提高。        如果發現有大量的線程都在處在 Wait on condition,從線程 stack看, 正等待網絡讀寫,這可能是一個網絡瓶頸的征兆。因為網絡阻塞導致線程無法執行。一種情況是網絡非常忙,幾 乎消耗了所有的帶寬,仍然有大量數據等待網絡讀 寫;另一種情況也可能是網絡空閑,但由于路由等問題,導致包無法正常的到達。所以要結合系統的一些性能觀察工具來綜合分析,比如 netstat統計單位時間的發送包的數目,如果很明顯超過了所在網絡帶寬的限制 ; 觀察 cpu的利用率,如果系統態的 CPU時間,相對于用戶態的 CPU時間比例較高;如果程序運行在 Solaris 10平臺上,可以用 dtrace工具看系統調用的情況,如果觀察到 read/write的系統調用的次數或者運行時間遙遙領先;這些都指向由于網絡帶寬所限導致的網絡瓶頸。另外一種出現 Wait on condition的常見情況是該線程在 sleep,等待 sleep的時間到了時候,將被喚醒。1.3 Waiting for monitor entry 和 in Object.wait()          在多線程的 JAVA程序中,實現線程之間的同步,就要說說 Monitor。 Monitor是 Java中用以實現線程之間的互斥與協作的主要手段,它可以看成是對象或者 Class的鎖。每一個對象都有,也僅有一個 monitor。每個 Monitor在某個時刻,只能被一個線程擁有,該線程就是 “Active Thread”,而其它線程都是 “Waiting Thread”,分別在兩個隊列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的線程狀態是 “Waiting for monitor entry”,而在 “Wait Set”中等待的線程狀態是 “in Object.wait()”。        先看 “Entry Set”里面的線程。我們稱被 synchronized保護起來的代碼段為臨界區。當一個線程申請進入臨界區時,它就進入了 “Entry Set”隊列。

對應的 code就像:

synchronized(obj) {.........}這時有兩種可能性:     該 monitor不被其它線程擁有, Entry Set里面也沒有其它等待線程。本線程即成為相應類或者對象的 Monitor的 Owner,執行臨界區的代碼     該 monitor被其它線程擁有,本線程在 Entry Set隊列中等待。 在第一種情況下,線程將處于 “Runnable”的狀態,而第二種情況下,線程 DUMP會顯示處于 “waiting for monitor entry”。如下所示:
"Thread-0" prio=10 tid=0x08222eb0 nid=0x9 waiting for monitor entry [0xf927b000..0xf927bdb8]  at testthread.WaitThread.run(WaitThread.java:39)  - waiting to lock <0xef63bf08> (a java.lang.Object)  - locked <0xef63beb8> (a java.util.ArrayList) at java.lang.Thread.run(Thread.java:595)   臨界區的設置,是為了保證其內部的代碼執行的原子性和完整性。但是因為臨界區在任何時間只允許線程串行通過,這 和我們多線程的程序的初衷是相反的。 如果在多線程的程序中,大量使用 synchronized,或者不適當的使用了它,會造成大量線程在臨界區的入口等待,造成系統的性能大幅下降。如果在線程 DUMP中發現了這個情況,應該審查源碼,改進程序。        現在我們再來看現在線程為什么會進入 “Wait Set”。當線程獲得了 Monitor,進入了臨界區之后,如果發現線程繼續運行的條件沒有滿足,它則調用對象(一般就是被 synchronized 的對象)的 wait() 方法,放棄了 Monitor,進入 “Wait Set”隊列。只有當別的線程在該對象上調用了 notify() 或者 notifyAll() , “ Wait Set”隊列中線程才得到機會去競爭,但是只有一個線程獲得對象的 Monitor,恢復到運行態。在 “Wait Set”中的線程, DUMP中表現為: in Object.wait(),類似于:
"Thread-1" prio=10 tid=0x08223250 nid=0xa in Object.wait() [0xef47a000..0xef47aa38]          at java.lang.Object.wait(Native Method)          - waiting on <0xef63beb8> (a java.util.ArrayList)          at java.lang.Object.wait(Object.java:474)          at testthread.MyWaitThread.run(MyWaitThread.java:40)          - locked <0xef63beb8> (a java.util.ArrayList)          at java.lang.Thread.run(Thread.java:595)仔細觀察上面的 DUMP信息,你會發現它有以下兩行:- locked <0xef63beb8> (a java.util.ArrayList)- waiting on <0xef63beb8> (a java.util.ArrayList) 這里需要解釋一下,為什么先 lock了這個對象,然后又 waiting on同一個對象呢?讓我們看看這個線程對應的代碼:
synchronized(obj) {         .........         obj.wait();         .........  }線程的執行中,先用 synchronized 獲得了這個對象的 Monitor(對應于 locked <0xef63beb8> )。當執行到 obj.wait(), 線程即放棄了 Monitor的所有權,進入 “wait set”隊列(對應于 waiting on <0xef63beb8> )。         往往在你的程序中,會出現多個類似的線程,他們都有相似的 DUMP信息。這也可能是正常的。比如,在程序中,有多個服務線程,設計成從一個隊列里面讀取請求數據。這個隊列就是 lock以及 waiting on的對象。當隊列為空的時候,這些線程都會在這個隊列上等待,直到隊列有了數據,這些線程被 Notify,當然只有一個線程獲得了 lock,繼續執行,而其它線程繼續等待。3. JDK 5.0 的 lock         上面我們提到如果 synchronized和 monitor機制運用不當,可能會造成多線程程序的性能問題。在 JDK 5.0中,引入了 Lock機制,從而使開發者能更靈活的開發高性能的并發多線程程序,可以替代以往 JDK中的 synchronized和 Monitor的 機制。但是,要注意的是,因為 Lock類只是一個普通類, JVM無從得知 Lock對象的占用情況,所以在線程 DUMP中,也不會包含關于 Lock的信息, 關于死鎖等問題,就不如用 synchronized的編程方式容易識別。4.案例分析 1.     死鎖在多線程程序的編寫中,如果不適當的運用同步機制,則有可能造成程序的死鎖,經常表現為程序的停頓,或者不再響應用戶的請求。比如在下面這個示例中,是個較為典型的死鎖情況:
"Thread-1" prio=5 tid=0x00acc490 nid=0xe50 waiting for monitor entry [0x02d3f0000x02d3fd68]  at deadlockthreads.TestThread.run(TestThread.java:31)  - waiting to lock <0x22c19f18> (a java.lang.Object)  - locked <0x22c19f20> (a java.lang.Object)  "Thread-0" prio=5 tid=0x00accdb0 nid=0xdec waiting for monitor entry [0x02cff0000x02cff9e8]  at deadlockthreads.TestThread.run(TestThread.java:31)  - waiting to lock <0x22c19f20> (a java.lang.Object)  - locked <0x22c19f18> (a java.lang.Object) 在 JAVA 5中加強了對死鎖的檢測。線程 Dump中可以直接報告出 Java級別的死鎖,如下所示:
Found one Java-level deadlock:  =============================  "Thread-1":  waiting to lock monitor 0x0003f334 (object 0x22c19f18, a java.lang.Object),  which is held by "Thread-0"  "Thread-0":  waiting to lock monitor 0x0003f314 (object 0x22c19f20, a java.lang.Object),  which is held by "Thread-1" 2.     熱鎖        熱鎖,也往往是導致系統性能瓶頸的主要因素。其表現特征為,由于多個線程對臨界區,或者鎖的競爭,可能出現:    * 頻繁的線程的上下文切換:從操作系統對線程的調度來看,當 線程在等待資源而阻塞的時候,操作系統會將之切換出來,放到等待的隊列,當線程獲得資源之后,調度算法會將這個線程切換進去,放到執行隊列中。    * 大量的系統調用:因為線程的上下文切換,以及熱鎖的競爭,或 者臨界區的頻繁的進出,都可能導致大量的系統調用。    * 大部分 CPU開銷用在 “系統態 ”:線程上下文切換,和系統調用,都會導致 CPU在 “系統態 ”運行,換而言之,雖然系統很忙碌,但是 CPU用在 “用戶態 ”的比例較小,應用程序得不到充分的 CPU資源。     * 隨著 CPU數目的增多,系統的性能反而下降。因為 CPU數目多,同 時運行的線程就越多,可能就會造成更頻繁的線程上下文切換和系統態的 CPU開銷,從而導致更糟糕的性能。 上面的描述,都是一個 scalability(可擴展性)很差的系統的表現。從整體的性能指標看,由于線程熱鎖的存在,程序的響應時間會變長,吞吐量會降低。         那么,怎么去了解 “熱鎖 ”出現在什么地方呢?一個重要的方法還是結合操作系統的各種工具觀察系統資源使用狀況,以及收集 Java線程的 DUMP信息,看線程都阻塞在什么方法上,了解原因,才能找到對應的解決方法。        我們曾經遇到過這樣的例子,程序運行時,出現了以上指出的各種現象,通過觀察操作系統的資源使用統計信息,以及線程 DUMP信息,確定了程序中熱鎖的存在,并發現大多數的線程狀態都是 Waiting for monitor entry或者 Wait on monitor,且是阻塞在壓縮和解壓縮的方法上。后來采用第三方的壓縮包 javalib替代 JDK自帶的壓縮包后,系統的性能提高了幾倍。

在 JAVA 5中加強了對死鎖的檢測。線程 Dump中可以直接報告出 Java級別的死鎖,如下所示:
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久精品免费视频| 日韩精品www| 性亚洲最疯狂xxxx高清| 亚洲精品在线91| 中文字幕亚洲专区| 亚洲欧美在线播放| 日本道色综合久久影院| 亚洲免费小视频| 最近免费中文字幕视频2019| 国产成人一区二| 欧美老女人www| 午夜精品久久久久久久99黑人| 国产精品亚洲一区二区三区| 国产日韩精品在线观看| 亚洲人成网站999久久久综合| 国产精品7m视频| 亚洲第一区中文字幕| 中文字幕精品网| 国产在线观看一区二区三区| 国产97色在线|日韩| 国产亚洲成av人片在线观看桃| 日韩av综合中文字幕| 国产欧美日韩高清| 欧美性生交大片免费| 国产精品狠色婷| 欧洲亚洲妇女av| 爽爽爽爽爽爽爽成人免费观看| 国产精品久久久久久久久久ktv| 日韩风俗一区 二区| 亚洲欧美成人一区二区在线电影| 亚洲视频一区二区三区| 97国产精品久久| 欧美成人精品三级在线观看| 午夜精品美女自拍福到在线| 精品国产精品自拍| 成人国产精品一区二区| 国产91热爆ts人妖在线| 亚洲综合小说区| 欧美午夜性色大片在线观看| 亚洲成人黄色在线| 亚洲欧美中文在线视频| 亚洲成色777777女色窝| 国产精品777| 日本国产欧美一区二区三区| 狠狠躁夜夜躁人人躁婷婷91| 色综合老司机第九色激情| 亚洲人成网站免费播放| 色综合视频一区中文字幕| 亚洲free性xxxx护士白浆| 亚洲已满18点击进入在线看片| 国产精品稀缺呦系列在线| 欧美激情综合色| 亚洲国产精品系列| 国产一区香蕉久久| 大伊人狠狠躁夜夜躁av一区| 欧美日韩国产激情| 欧美性生交大片免费| 亚洲一区二区免费在线| 成人妇女淫片aaaa视频| 深夜福利日韩在线看| 久久99青青精品免费观看| 欧美一区第一页| 精品亚洲一区二区三区在线播放| 欧美综合一区第一页| 色先锋久久影院av| 亚洲天堂av高清| 亚洲一区二区久久久久久久| 亚洲欧美国产日韩天堂区| 亚洲成人网av| 庆余年2免费日韩剧观看大牛| 丰满岳妇乱一区二区三区| 亚洲欧美制服丝袜| 亚州欧美日韩中文视频| 日韩一区二区欧美| 狠狠色狠狠色综合日日五| 国产精品激情av电影在线观看| 欧美自拍大量在线观看| 一本色道久久88亚洲综合88| 欧美一级bbbbb性bbbb喷潮片| 91国内揄拍国内精品对白| 国产精品日韩专区| 亚洲精品成人久久电影| 亚洲成人精品视频| www.美女亚洲精品| 欧美中文在线免费| 亚洲精品电影久久久| 国内精品一区二区三区四区| 欧美有码在线观看视频| 国产精品国产三级国产aⅴ9色| 欧美老女人性生活| 欧美一区三区三区高中清蜜桃| 国产精品久久久久91| 日韩在线高清视频| 亚洲天天在线日亚洲洲精| 日本精品久久久| 亚洲自拍中文字幕| 亚洲第一视频在线观看| 国产日韩在线免费| 国产精品久久久久久久美男| 91免费看片在线| 欧美日韩成人黄色| 亚洲欧美日韩图片| 国产亚洲aⅴaaaaaa毛片| 国产精品白丝jk喷水视频一区| 成人黄色片网站| 国产精品亚洲第一区| 亚洲最新中文字幕| 国产日韩精品视频| 日韩专区中文字幕| 国语自产在线不卡| 亚洲国产精品女人久久久| 九色精品免费永久在线| 精品综合久久久久久97| 精品一区二区三区电影| 91社影院在线观看| 国产精品久久久久久久久久| 欧美激情精品久久久久久变态| 亚洲精品电影在线| www.久久草.com| 日韩精品丝袜在线| 在线观看日韩欧美| 久久亚洲精品小早川怜子66| 久久久欧美精品| 亚洲精品久久7777777| 亚洲国产成人精品女人久久久| 色噜噜狠狠色综合网图区| 色噜噜狠狠狠综合曰曰曰88av| 成人精品一区二区三区电影免费| 国产精品久久999| 国语自产精品视频在线看| 热re99久久精品国产66热| 欧美老女人www| 在线视频日本亚洲性| 欧美大尺度电影在线观看| 国产日韩欧美视频| 97在线视频免费观看| 欧美日韩国产精品一区二区三区四区| 国内精品在线一区| 欧美激情中文字幕乱码免费| 欧美又大又硬又粗bbbbb| 久久中文久久字幕| 精品高清一区二区三区| 亚洲欧美国产视频| 欧美精品在线免费播放| 欧美老女人性生活| 丝袜亚洲另类欧美重口| 久久久久国产精品免费网站| 亚洲第一国产精品| 日本一区二区三区四区视频| 韩国一区二区电影| 久久综合网hezyo| 国产精品一区专区欧美日韩| 亚洲电影免费观看高清| 91视频国产精品| 久久理论片午夜琪琪电影网| 日本在线精品视频| 亚洲护士老师的毛茸茸最新章节| 视频一区视频二区国产精品| 久久成人亚洲精品| 亚洲自拍小视频免费观看| 亚洲综合成人婷婷小说| www国产亚洲精品久久网站| 亚洲第一精品自拍| 日韩网站免费观看|