JVM 問題排查
CPU使用率高
- 找出使用率高的程式的pid
top
- 找出使用率高的執行緒tpid
top -p pid -H
- 檢視使用率高的執行緒當前在幹什麼
jstack -l pid > stack.log
// 將執行緒的tpid轉為16進位制,到stack.log中查詢
grep tpid stack.log -a3
GC問題
// -t:列印時間戳,1s每隔1秒列印一次
jstat -gcutil -t pid 1s
也可以通過檢視gc日誌來觀察問題
記憶體洩漏
- 執行FullGC後不能回收的記憶體不斷增加
- 執行jstat -gcutil pid,檢視Old區的使用情況,如果接近100%,則代表記憶體不足。可以先增大記憶體,如果還是不斷增長到溢位,則考慮是否有記憶體洩漏問題
- 執行jmap -histo:live pid > memory.log,統計所有存活物件的個數,觀察那些數量最多的物件,特別是自己寫的物件和存放到集合裡沒有釋放的物件
- 如果還是無法定位,則執行jmap -dump匯出整個Heap,然後使用工具進行分析,注意看自己寫的類的依賴關係,看看是不是使用完沒有釋放,或者一次性查詢過多的資料導致記憶體溢位
執行緒分析
如果CPU使用率不高,但程式效能低下,則可考慮對執行緒進行分析,看看各個主要的執行緒都在做什麼,是否有鎖爭用或IO阻塞問題
為了方便分析,最好給每個執行緒或者執行緒池命名
jstack -l pid > stack.log
執行緒狀態
狀態 | 描述 |
---|---|
New | 執行緒剛被建立,還沒有被執行 |
Runnable | 執行緒正在執行 |
Blocked | 等待其他執行緒釋放鎖 |
Waiting | 呼叫了wait或join方法,無限等待 |
Timed_Waiting | 呼叫了sleep、wait(interval)、join(interval)方法,有限等待 |
觀察
死鎖
如果JVM發現有死鎖存在,會在日誌中出現Found one Java-level deadlock
Waiting on condition
在等待一個條件的發生,來把自己喚醒,或者呼叫了sleep方法
此時執行緒狀態:
WAITING(parking):一直等待那個條件發生
TIMED_WAITING(parking或sleeping):定時等待,即使條件不發生,時間到了也可以自己喚醒
如果發現大量執行緒處於此狀態,並且從執行緒的堆疊上檢視到是正在執行網路讀寫,這可能是一個網路瓶頸問題或者第三方響應慢的問題
Blocked
執行緒所需要的資源長時間等待卻一直無法獲取,被標識為阻塞狀態,可以理解為等待資源超時的執行緒。執行緒堆疊中一般存在Waiting to Lock
Waiting for monitor entry 和 in Object.wait()
每個 Monitor在某個時刻,只能被一個執行緒擁有,該執行緒就是Active Thread,而其它執行緒都是Waiting Thread,分別在兩個佇列 Entry Set和Wait Set裡面等候。 在Entry Set中等待的執行緒狀態是Waiting for monitor entry,而在Wait Set中等待的執行緒狀態是in Object.wait()。當被呼叫notify或notifyAll時,只有在Wait Set中的執行緒會被喚醒
Waiting for monitor entry:等待進入一個臨界區 ,所以它在Entry Set佇列中等待。此時執行緒狀態一般都是Blocked,如果存在大量執行緒在此狀態,可能是一個全域性鎖阻塞住了大量執行緒。隨著時間流逝,waiting for monitor entry的執行緒越來越多,沒有減少的趨勢,可能意味著某些執行緒在臨界區裡呆的時間太長了,以至於越來越多新執行緒遲遲無法進入臨界區
當執行緒獲得了Monitor,如果發現執行緒繼續執行的條件沒有滿足,它則呼叫物件(一般就是被 synchronized 的物件)的 wait() 方法,放棄了Monitor,進入Wait Set佇列。此時執行緒狀態大致為以下幾種:TIMED_WAITING (on object monitor)和 WAITING (on object monitor)
等待IO
有時候執行緒狀態是Runnable,但卻是在等待IO
"socketReadThread" prio=6 tid=0x0000000006a0d800 nid=0x1b40 runnable
[0x00000000089ef000] java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
總結
- 如果cpu使用率不高,但效能低下,一般都是由鎖或IO阻塞造成,這時要注意檢視狀態為BLOCKED或者Waiting的執行緒,看它們需要等待什麼鎖或者是否出現了死鎖,再考慮如何優化併發
- 如果發現有大量的執行緒都在處在 Wait on condition,從執行緒 stack看,正等待網路讀寫,這可能是一個網路瓶頸的徵兆。因為網路阻塞導致執行緒無法執行。一種情況是網路非常忙,幾乎消耗了所有的頻寬,仍然有大量資料等待網路讀寫;另一種情況也可能是網路空閒,但由於路由等問題,導致包無法正常的到達
參考
相關文章
- JVM問題排查步驟JVM
- Linux排查JVM問題LinuxJVM
- 使用jvm工具排查系統問題JVM
- JVM堆外記憶體問題排查JVM記憶體
- JVM 常見線上問題 → CPU 100%、記憶體洩露 問題排查JVM記憶體洩露
- JVM執行緒和記憶體溢位問題排查思路JVM執行緒記憶體溢位
- java問題排查Java
- 框架問題排查框架
- 技能篇:linux服務效能問題排查及jvm調優思路LinuxJVM
- SDK與問題排查
- 線上FullGC問題排查實踐——手把手教你排查線上問題GC
- Java服務.問題排查.問題復現Java
- 異常問題排查之旅
- Spark學習——問題排查Spark
- 利用greys排查java問題Java
- 資料問題排查思路
- Redis阻塞問題排查方向Redis
- Mysql show processlist 排查問題MySql
- JAVA死鎖排查-效能測試問題排查思路Java
- JVM問題及解答JVM
- JVM 問題分析思路JVM
- JVM問題定位工具JVM
- jvm常問問題目錄JVM
- JVM 線上故障排查基本操作JVM
- 微信支付返回-1,問題排查
- 運維排查問題常用sql運維SQL
- 伺服器問題 排查思路伺服器
- 日常問題排查-呼叫超時
- kubernetesgraceperiod失效問題排查
- 排查 “Detected Tx Unit Hang”問題
- 線上效能問題初步排查方法
- TNS問題排查 The listener supports no services
- 【問題追查】mc叢集寫入恍惚問題排查
- 記一次oom問題排查OOM
- 記錄一次問題排查
- 線上問題排查神器入門——Arthas
- redis connect timeout問題排查Redis
- RDSforSQLserver空間問題排查彙總SQLServer