天天看點

jstack問題定位分析

jstack

jstack

java虛拟機

自帶的一種

堆棧跟蹤工具

jstack

用于列印出給定的

java程序ID

core file

遠端調試服務

的Java堆棧資訊。

jstack主要用于生成java虛拟機目前時刻的線程快照,線程快照是目前java虛拟機内每一條線程正在執行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現長時間停頓的原因,如線程間死鎖、死循環、請求外部資源導緻的長時間等待等。

線程出現停頓的時候通過jstack來檢視各個線程的調用堆棧,就可以知道沒有響應的線程到底在背景做什麼事情,或者等待什麼資源。

top指令

在linux環境下,可以通過

top

指令檢視各個程序的cpu使用情況,預設按cpu使用率排序。

jstack指令

通過top指令定位到cpu占用率較高的線程之後,繼續使用

jstack pid

指令檢視目前java程序的堆棧狀态。

jstack指令生成的thread dump資訊包含了JVM中所有存活的線程,為了分析指定線程,必須找出對應線程的調用棧,應該如何找?

在top指令中,已經擷取到了占用cpu資源較高的線程pid,将該pid轉成16進制的值,在thread dump中每個線程都有一個nid,找到對應的nid即可;隔段時間再執行一次stack指令擷取thread dump,區分兩份dump是否有差别。

線程5種狀态

建立狀态(New) 新建立了一個線程對象。

就緒狀态(Runnable) 線程對象建立後,其他線程調用了該對象的start()方法。該狀态的線程位于可運作線程池中,變得可運作,等待擷取CPU的使用權。

運作狀态(Running) 就緒狀态的線程擷取了CPU,執行程式代碼。

阻塞狀态(Blocked) 阻塞狀态是線程因為某種原因放棄CPU使用權,暫時停止運作。直到線程進入就緒狀态,才有機會轉到運作狀态。

阻塞的情況分三種:

  • 等待阻塞:運作的線程執行wait()方法,JVM會把該線程放入等待池中。
  • 同步阻塞:運作的線程在擷取對象的同步鎖時,若該同步鎖被别的線程占用,則JVM會把該線程放入鎖池中。
  • 其他阻塞:運作的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀态。當sleep()狀态逾時、join()等待線程終止或者逾時、或者I/O處理完畢時,線程重新轉入就緒狀态。

死亡狀态(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

通過thread dump分析線程狀态

基于thead dump分析目前各個線程的運作情況,如是否存在死鎖、是否存在一個線程長時間持有鎖不放等等。

在dump中,線程一般存在如下幾種狀态:

  • RUNNABLE,線程運作中或I/O等待
  • BLOCKED,線程被阻塞,在等待monitor鎖(synchronized關鍵字)
  • TIMED_WAITING 線程在等待喚醒,但設定了時限
  • WAITING 線程在無限等待喚醒

log4j 1.X版本引發線程blocked死鎖問題(synchronized同步鎖)

jstack問題定位分析

線程處于BLOCK狀态。

  • 該線程是blocked在了log4j.Category.callAppenders上,顯然可以發現這是個log4j的問題。
  • 解決方法:使用log4j2或者使用slf4j替代直接使用log4j

wait挂起線程

jstack問題定位分析

線程1和2都處于WAITING狀态

  • 線程1和2都是先

    locked <0x000000076bf62500>

    ,再

    waiting on <0x000000076bf62500>

    ,之是以先鎖再等同一個對象,是因為wait方法需要先通過synchronized獲得該位址對象的monitor;
  • waiting on <0x000000076bf62500>

    說明線程執行了wait方法之後,釋放了monitor,進入到"Wait Set"隊列,等待其它線程執行位址為0x000000076bf62500對象的notify方法,并喚醒自己 

連接配接池

jstack問題定位分析

線程處于WAITING狀态

  • 多執行幾次jstack可以發現大約有部分的線程處于waitting狀态,該狀态表明該線程正在執行obj.wait()方法,放棄了 Monitor,進入 “Wait Set”隊列,為什麼阻塞住呢,繼續往下看堆棧資訊,可以看到該線程正在做borrowobject操作,可以大概看到這裡是一個資料庫連接配接池的相關操作,可以适當調整資料庫連接配接池大小