<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java程序員必備:jstack命令解析

          共 5848字,需瀏覽 12分鐘

           ·

          2021-04-25 21:53

          走過路過不要錯過

          點擊藍字關(guān)注我們


          前言

          如果有一天,你的Java程序長時間停頓,也許是它病了,需要用jstack拍個片子分析分析,才能診斷具體什么病癥,是死鎖綜合征,還是死循環(huán)等其他病癥,本文我們一起來學(xué)習(xí)jstack命令~

          • jstack 的功能

          • jstack用法

          • 線程狀態(tài)等基礎(chǔ)回顧

          • 實戰(zhàn)案例1:jstack 分析死鎖

          • 實戰(zhàn)案例2:jstack 分析CPU 過高

          jstack 的功能

          jstack是JVM自帶的Java堆棧跟蹤工具,它用于打印出給定的java進程ID、core file、遠程調(diào)試服務(wù)的Java堆棧信息.

          jstack prints Java stack traces of Java threads for a given Java process orcore file or a remote debug server. 
          • jstack命令用于生成虛擬機當(dāng)前時刻的線程快照。

          • 線程快照是當(dāng)前虛擬機內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現(xiàn)長時間停頓的原因, 如線程間死鎖、死循環(huán)、請求外部資源導(dǎo)致的長時間等待等問題。

          • 線程出現(xiàn)停頓的時候通過jstack來查看各個線程的調(diào)用堆棧,就可以知道沒有響應(yīng)的線程到底在后臺做什么事情,或者等待什么資源。

          • 如果java程序崩潰生成core文件,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發(fā)生問題。

          • 另外,jstack工具還可以附屬到正在運行的java程序中,看到當(dāng)時運行的java程序的java stack和native stack的信息, 如果現(xiàn)在運行的java程序呈現(xiàn)hung的狀態(tài),jstack是非常有用的。

          jstack用法

          jstack 命令格式如下

          jstack [ option ] pidjstack [ option ] executable corejstack [ option ] [server-id@]remote-hostname-or-IP 
          • executable Java executable from which the core dump was produced.(可能是產(chǎn)生core dump的java可執(zhí)行程序)

          • core 將被打印信息的core dump文件

          • remote-hostname-or-IP 遠程debug服務(wù)的主機名或ip

          • server-id 唯一id,假如一臺主機上多個遠程debug服務(wù)

          最常用的是

          jstack [option] <pid>  // 打印某個進程的堆棧信息

          option參數(shù)說明如下:

          線程狀態(tài)等基礎(chǔ)回顧

          線程狀態(tài)簡介

          jstack用于生成線程快照的,我們分析線程的情況,需要復(fù)習(xí)一下線程狀態(tài)吧,拿小凳子坐好,復(fù)習(xí)一下啦~



          Java語言定義了6種線程池狀態(tài):

          • New:創(chuàng)建后尚未啟動的線程處于這種狀態(tài),不會出現(xiàn)在Dump中。

          • RUNNABLE:包括Running和Ready。線程開啟start()方法,會進入該狀態(tài),在虛擬機內(nèi)執(zhí)行的。

          • Waiting:無限的等待另一個線程的特定操作。

          • Timed Waiting:有時限的等待另一個線程的特定操作。

          • 阻塞(Blocked):在程序等待進入同步區(qū)域的時候,線程將進入這種狀態(tài),在等待監(jiān)視器鎖。

          • 結(jié)束(Terminated):已終止線程的線程狀態(tài),線程已經(jīng)結(jié)束執(zhí)行。

          Dump文件的線程狀態(tài)一般其實就以下3種:

          • RUNNABLE,線程處于執(zhí)行中

          • BLOCKED,線程被阻塞

          • WAITING,線程正在等待

          Monitor 監(jiān)視鎖

          因為Java程序一般都是多線程運行的,Java多線程跟監(jiān)視鎖環(huán)環(huán)相扣,所以我們分析線程狀態(tài)時,也需要回顧一下Monitor監(jiān)視鎖知識。

          Monitor的工作原理圖如下:



          • 線程想要獲取monitor,首先會進入Entry Set隊列,它是Waiting Thread,線程狀態(tài)是Waiting for monitor entry。

          • 當(dāng)某個線程成功獲取對象的monitor后,進入Owner區(qū)域,它就是Active Thread。

          • 如果線程調(diào)用了wait()方法,則會進入Wait Set隊列,它會釋放monitor鎖,它也是Waiting Thread,線程狀態(tài)in Object.wait()

          • 如果其他線程調(diào)用 notify() / notifyAll() ,會喚醒Wait Set中的某個線程,該線程再次嘗試獲取monitor鎖,成功即進入Owner區(qū)域。

          Dump 文件分析關(guān)注重點

          • runnable,線程處于執(zhí)行中

          • deadlock,死鎖(重點關(guān)注)

          • blocked,線程被阻塞 (重點關(guān)注)

          • Parked,停止

          • locked,對象加鎖

          • waiting,線程正在等待

          • waiting to lock 等待上鎖

          • Object.wait(),對象等待中

          • waiting for monitor entry 等待獲取監(jiān)視器(重點關(guān)注)

          • Waiting on condition,等待資源(重點關(guān)注),最常見的情況是線程在等待網(wǎng)絡(luò)的讀寫

          實戰(zhàn)案例1:jstack 分析死鎖問題

          • 什么是死鎖?

          • 如何用jstack排查死鎖?

          什么是死鎖?



          死鎖是指兩個或兩個以上的線程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法進行下去。

          如何用如何用jstack排查死鎖問題

          先來看一段會產(chǎn)生死鎖的Java程序,源碼如下:

          /** * Java 死鎖demo */public class DeathLockTest {private static Lock lock1 = new ReentrantLock();private static Lock lock2 = new ReentrantLock();
          public static void deathLock() { Thread t1 = new Thread() { @Overridepublic void run() {try { lock1.lock(); System.out.println(Thread.currentThread().getName() + " get the lock1"); Thread.sleep(1000); lock2.lock(); System.out.println(Thread.currentThread().getName() + " get the lock2"); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread t2 = new Thread() { @Overridepublic void run() {try { lock2.lock(); System.out.println(Thread.currentThread().getName() + " get the lock2"); Thread.sleep(1000); lock1.lock(); System.out.println(Thread.currentThread().getName() + " get the lock1"); } catch (InterruptedException e) { e.printStackTrace(); } } };//設(shè)置線程名字,方便分析堆棧信息 t1.setName("mythread-jay"); t2.setName("mythread-tianluo"); t1.start(); t2.start(); }public static void main(String[] args) { deathLock(); }}

          運行結(jié)果:


          顯然,線程jay和線程tianluo都是只執(zhí)行到一半,就陷入了阻塞等待狀態(tài)~


          jstack排查Java死鎖步驟

          • 在終端中輸入jsp查看當(dāng)前運行的java程序

          • 使用 jstack -l pid 查看線程堆棧信息

          • 分析堆棧信息

          在終端中輸入jsp查看當(dāng)前運行的java程序


          通過使用 jps 命令獲取需要監(jiān)控的進程的pid,我們找到了23780 DeathLockTest


          使用 jstack -l pid 查看線程堆棧信息


          由上圖,可以清晰看到死鎖信息:


          • mythread-tianluo 等待這個鎖 “0x00000000d61ae3a0”,這個鎖是由于mythread-jay線程持有。

          • mythread-jay線程等待這個鎖“0x00000000d61ae3d0”,這個鎖是由mythread-tianluo 線程持有。

          還原死鎖真相


          “mythread-tianluo"線程堆棧信息分析如下:


          • mythread-tianluo的線程處于等待(waiting)狀態(tài),持有“0x00000000d61ae3d0”鎖,等待“0x00000000d61ae3a0”的鎖

          “mythread-jay"線程堆棧信息分析如下:

          • mythread-tianluo的線程處于等待(waiting)狀態(tài),持有“0x00000000d61ae3a0”鎖,等待“0x00000000d61ae3d0”的鎖




          實戰(zhàn)案例2:jstack 分析CPU過高問題

          來個導(dǎo)致CPU過高的demo程序,一個死循環(huán),哈哈~

          /** * 有個導(dǎo)致CPU過高程序的demo,死循環(huán) */public class JstackCase {
          private static ExecutorService executorService = Executors.newFixedThreadPool(5);
          public static void main(String[] args) {
          Task task1 = new Task(); Task task2 = new Task(); executorService.execute(task1); executorService.execute(task2); }
          public static Object lock = new Object();
          static class Task implements Runnable{
          public void run() { synchronized (lock){long sum = 0L;while (true){ sum += 1; } } } }}

          jstack 分析CPU過高步驟

            1. top

            2. top -Hp pid

            3. jstack pid

            4. jstack -l [PID] >/tmp/log.txt

            5. 分析堆棧信息

          1.top

          在服務(wù)器上,我們可以通過top命令查看各個進程的cpu使用情況,它默認是按cpu使用率由高到低排序的


          由上圖中,我們可以找出pid為21340的java進程,它占用了最高的cpu資源,兇手就是它,哈哈!


          2. top -Hp pid

          通過top -Hp 21340可以查看該進程下,各個線程的cpu使用情況,如下:


          可以發(fā)現(xiàn)pid為21350的線程,CPU資源占用最高~,嘻嘻,小本本把它記下來,接下來拿jstack給它拍片子~


          3. jstack pid

          通過top命令定位到cpu占用率較高的線程之后,接著使用jstack pid命令來查看當(dāng)前java進程的堆棧狀態(tài),jstack 21350后,內(nèi)容如下:



          4. jstack -l [PID] >/tmp/log.txt

          其實,前3個步驟,堆棧信息已經(jīng)出來啦。但是一般在生成環(huán)境,我們可以把這些堆棧信息打到一個文件里,再回頭仔細分析哦~

          5. 分析堆棧信息

          我們把占用cpu資源較高的線程pid(本例子是21350),將該pid轉(zhuǎn)成16進制的值


          在thread dump中,每個線程都有一個nid,我們找到對應(yīng)的nid(5366),發(fā)現(xiàn)一直在跑(24行)




          這個時候,可以去檢查代碼是否有問題啦~ 當(dāng)然,也建議隔段時間再執(zhí)行一次stack命令,再一份獲取thread dump,畢竟兩次拍片結(jié)果(jstack)對比,更準確嘛~




          往期精彩推薦



          騰訊、阿里、滴滴后臺面試題匯總總結(jié) — (含答案)

          面試:史上最全多線程面試題 !

          最新阿里內(nèi)推Java后端面試題

          JVM難學(xué)?那是因為你沒認真看完這篇文章


          END


          關(guān)注作者微信公眾號 —《JAVA爛豬皮》


          了解更多java后端架構(gòu)知識以及最新面試寶典


          你點的每個好看,我都認真當(dāng)成了


          看完本文記得給作者點贊+在看哦~~~大家的支持,是作者源源不斷出文的動力

          瀏覽 175
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人黄色片在线免费看 | 色色五月天视频 | 国产一区二区性爱视频 | 三级片小说网站一区 | 国产乱╳╳aⅴ老师 |