1. 程式人生 > >jvm程式執行慢診斷手冊

jvm程式執行慢診斷手冊

生產環境最多的幾種事故之一就是程式執行慢,如果是web服務的話,表現就是響應時間長。本文分享,從業多年形成的排查守則。

診斷步驟

系統資源檢視

首先是系統資源檢視,而且必須是在第一步。因為很多事故都是最開始慢後面就會出現卡死,被系統殺死,程式丟擲異常結束等等情況,當時的狀態沒法儲存下來,不行進行復盤,所以第一步先檢視系統的資源,如果出現緊張情況,趕緊把狀態儲存。

top命令

檢視基本就是top命令,可以看到系統cpu,記憶體等資源情況。經過檢視系統資源大概可以分為以下情況。

問題:cpu使用率過高。

如果發現cpu成為了瓶頸的話,必須馬上進行執行緒情況和當時cpu佔用情況的儲存。在糟糕的情況下,cpu可能被佔滿,那時候ssh都登入不上去了,就沒法獲取當時的情況。

使用top -Hp pid獲取執行緒cpu使用率高的tid
printf "%x\n" tid,獲取執行緒id的16進位制主要是為了在jstack中檢視
jstack pid|grep tid(16)

然後就會把執行緒cpu使用率特別高的執行緒棧打出來,然後可以分析這段邏輯了。

記憶體使用率過高或者沒有系統資源佔用過高

jmap -dump:format=b,file=heapdump.bin pid

這裡必須打dump的原因是res過高,可能出發系統的oom killer,程序可能被系統殺死,此時不獲取,可能程序就會被殺死了。如果不是系統資源問題,堆dump以後也是要用的。

堆佔用檢視

jstat -gc -h 10 pid 1000
jstat -gcutil -h 10 pid 1000
jstat -gccause -h 10 pid 1000

這裡一般是開三個視窗對比看資料的。-gc主要是關注堆的分割槽總大小。-gcutil主要是關注已使用的百分比。-gccause主要是關注fgc次數,時間以及gc原因。

記憶體問題的分類就比較多了,造成問題的卡頓的根本其實是gc問題。stw的時候虛擬機器停頓了,導致反應不過來了。

問題:堆記憶體佔用空間接近滿

這種情況就利用mat去檢視dump分析吧,可能出現記憶體使用不合理或者記憶體洩漏,這裡需要根據程式碼來分析。

問題:perm,metaspace佔用接近滿

jps -lvm

檢視一下jvm引數設定,很可能是引數設定不合理,-XX:MetaspaceSize是發生gc的最小空間,這裡是不是設定太小。MaxMetaspaceSize,MaxPermSize的值是否設定太小。java6如果設定都不小而且還佔滿了,那就得檢測程式碼裡是不是在執行時常量池加了字串。1.7,1.8就考慮是不是業務用了什麼位元組碼生成技術,動態做了一些位元組碼操作。

問題:system.gc()

gccause檢視gc的原因是system.gc()。需要檢測是否用了rmi,使用了直接記憶體,或者業務程式碼呼叫了system.gc()。直接記憶體檢視現在沒有現成的工具。可以使用我在github上放著的小工具檢視。地址如下https://github.com/xpbob/jstatassist

問題:gc頻繁但不是system.gc()

空間都不是特別緊張,但是gc次數頻繁,並且不是system.gc()。那可能就是gc引數設定不對了,例如cms,老年代回收是一個2秒一次的輪訓操作,很有可能是現在的空間佔用每次都是滿足gc的條件的,於是出現了這種情況。

問題:gc時間特別長

gc時間特別長,這個就從gc演算法選擇還有記憶體情況來協調引數吧。但是有兩個特例,cms和g1。這兩個垃圾回收器都是有單執行緒回收的演算法的可能的,這裡需要gc日誌分析確認。

問題:堆佔用不大,res特別大

這種情況可能性太大,常見的是jni,jna操作,mmap檔案,直接記憶體使用,jdk的bug。需要根據實際情況來分析。

問題: 業務問題

如果以上表現都沒有的話,那需要不斷的打jstack去看執行緒棧的變化。這個只能是