title: JVM故障發(fā)現(xiàn)排除
date: 2017-12-08 21:20:40
tags:
- Java
- JVM
categories: JVM
最近做了服務(wù)器遷移之后,系統(tǒng)運行過程中出現(xiàn)了幾次發(fā)現(xiàn)不穩(wěn)定的情況。這次的經(jīng)歷又回想起之前幾次碰到類似的問題,類似的問題往往需要能快速排查定位、處理。但相關(guān)類似問題又不是經(jīng)常能夠碰到,每次出現(xiàn)問題都是手忙腳亂的查資料,今天根據(jù)《深入理解 Java 虛擬機》和自己簡單的經(jīng)驗做一下總結(jié),方便日后使用。
工具
目前可用的 JVM 監(jiān)控工具還是蠻多的,這里只列出實際操作中我使用的幾個。其中有命令行工具也有第可視化工具,從使用的便捷性上講,可視化的工具無疑是更好的。但生產(chǎn)環(huán)境處于安全,性能的考慮往往不開放遠(yuǎn)程連接,這時還是得用命令行工具處理。
命令行工具
jps:JVM 進(jìn)程狀況工具,主要作用是查看 LVMID,-v 參數(shù)可以輸出 JMV 啟動參數(shù)
-
jstat:JVM 統(tǒng)計信息監(jiān)控工具,主要是查看 GC 相關(guān)信息:
- -gc:監(jiān)視 Java 堆狀況
- -gccapacity:監(jiān)視 Java 堆狀況,最大,最小空間
- -gcutil:監(jiān)視 Java 堆狀況,已使用百分比
輸出列含義見文末
-
jinfo:Java 配置信息工具,查看設(shè)置 JVM 啟動參數(shù)
- 查看:-flag < name >:輸出指定名稱參數(shù)值,作為 jps -v 補充
- 設(shè)置:
- -flag [+|-] < name >:設(shè)置指定 JVM 參數(shù)的布爾值
- -flag < name > = < value >:設(shè)置指定 JVM 參數(shù)的值
-
jmap:Java 內(nèi)存映像工具,主要參數(shù):
- -dump:生成快照,例如:-dump:format=b,file=< filename.bin > < pid >
- -heap:顯示 Java 堆詳細(xì)信息
- -histo:像是堆中對象統(tǒng)計信息
- -permstat:以 ClassLoader 為統(tǒng)計口徑顯示永久代內(nèi)存狀況
jstack:Java 堆棧跟蹤工具,用于生成 JVM 當(dāng)前線程快照,-l 參數(shù)顯示關(guān)于加鎖信息,-F 參數(shù)強制 dump
可視化工具
- VisualVM:多合一故障處理工具,這個幾乎涵蓋了我用到上面命令行的所有功能
- MemoryAnalyzerTool:用于分析 dump 堆文件,對比 VisualVM 功能單一,但是提供了報表功能可以協(xié)助分析問題
問題排查一般思路
目前我在實際開發(fā)過程中碰到的 JVM 問題主要可以分類幾類:內(nèi)存溢出、系統(tǒng)運行緩慢、頻繁 FullGC
內(nèi)存溢出
這種場景是影響最惡劣,但也是最容易排查的。通常的錯誤就能告訴說明溢出區(qū)域:
- outOfMemoryError :年老代內(nèi)存不足
- outOfMemoryError:PermGen Space:永久代內(nèi)存不足
- outOfMemoryError:GC overhead limit exceed:垃圾回收時間占用系統(tǒng)運行時間的98%或以上
生產(chǎn)環(huán)境碰到這類情況為了確保系統(tǒng)可用,可以先使用 jstat 查看 Java 堆的空間使用情況確定到底是哪部分溢出,其最大可用空間是多少,然后直接擴大該區(qū)域空間即可。重啟時建議加上 -XX:+HeapDumpOnOutMemoryError 作為啟動參數(shù),在下次溢出可以獲得快照文件。
上面的做法作為臨時解決方案可以解決一般性的問題,但沒有系統(tǒng)的快照無法深入分析問題產(chǎn)生的原因,如果想分析問題根源需要在重啟前使用 jmap 生成快照。獲得快照文件后可以在本地使用可視化工具分析。使用 MemoryAnalyzer 打開快照文件就能獲得一個分析報表,里面列出了可能出現(xiàn)泄露的地方。目前我碰到的內(nèi)存溢出問題一般從這個分析報表里面就可以確定了,如果不能確定就需要根據(jù)加載的類,類的實例,引用關(guān)系進(jìn)一步分析了。
我目前碰到的都是 Java 堆的溢出,以上的思路基本可以解決。但除此還有其他的內(nèi)存溢出需要注意:
- Direct Memory
- 線程堆棧:StackOverflowError,OutOfMemoryError:unable to create new native thread
- Socket 緩沖區(qū):IOException:Too many open files
系統(tǒng)運行緩慢
系統(tǒng)運行緩慢可能出現(xiàn)的原因就比較多了,通常就是找到導(dǎo)致系統(tǒng)緩慢的具體代碼段,然后修復(fù)。一般化的解決思路是從系統(tǒng)到應(yīng)用,從應(yīng)用到線程。
具體來說:首先使用系統(tǒng)監(jiān)控工具(例如 top,vmstat)查看當(dāng)前系統(tǒng)運行狀況,確認(rèn)哪個應(yīng)用的資源占用過大,是否是 Java 應(yīng)用的問題;其次使用 jps 獲得具體應(yīng)用的 LVMID,根據(jù) LVMID 查看應(yīng)用的具體運行狀況,如線程情況,系統(tǒng)信息等。還可以根據(jù)系統(tǒng)工具 pidstat 進(jìn)一步查看線程的運行信息來輔助確定問題。以上基本就可以確定問題。
頻繁 FullGC
頻繁 FullGC 需要視情況而定,這里只討論 FullGC 頻繁,但又沒有觸發(fā) OOM 的排查。這種情況下 dump 快照,直接分析大對象比較靠譜。
本地應(yīng)用
如果是本地應(yīng)用或者可以遠(yuǎn)程訪問的應(yīng)用排查起來就更方便了,直接使用 VisualVM 連接上去,從系統(tǒng)到線程的一切信息都了如指掌,還可以直接運行 GC,dump 快照等。
-
關(guān)于工具使用的一些參考:
JVM性能調(diào)優(yōu)監(jiān)控工具jps、jstack、jmap、jhat、jstat、hprof使用詳解
-
jstat 輸出列含義:
S0C:年輕代中第一個survivor的容量 (字節(jié))
S1C:年輕代中第二個survivor的容量 (字節(jié))
S0U:年輕代中第一個survivor目前已使用空間 (字節(jié))
S1U:年輕代中第二個survivor目前已使用空間 (字節(jié))
EC:年輕代中Eden的容量 (字節(jié))
EU:年輕代中Eden目前已使用空間 (字節(jié))
OC:Old代的容量 (字節(jié))
OU:Old代目前已使用空間 (字節(jié))
PC:Perm(持久代)的容量 (字節(jié))
PU:Perm(持久代)目前已使用空間 (字節(jié))
YGC:從應(yīng)用程序啟動到采樣時年輕代中g(shù)c次數(shù)
YGCT:從應(yīng)用程序啟動到采樣時年輕代中g(shù)c所用時間(s)
FGC:從應(yīng)用程序啟動到采樣時old代(全gc)gc次數(shù)
FGCT:從應(yīng)用程序啟動到采樣時old代(全gc)gc所用時間(s)
GCT:從應(yīng)用程序啟動到采樣時gc用的總時間(s)
NGCMN:年輕代中初始化(最小)的大小 (字節(jié))
NGCMX:年輕代的最大容量 (字節(jié))
NGC:年輕代中當(dāng)前的容量 (字節(jié))
OGCMN:old代中初始化(最小)的大小 (字節(jié))
OGCMX:old代的最大容量 (字節(jié))
OGC:old代當(dāng)前新生成的容量 (字節(jié))
PGCMN:perm代中初始化(最小)的大小 (字節(jié))
PGCMX:perm代的最大容量 (字節(jié))
PGC:perm代當(dāng)前新生成的容量 (字節(jié))
S0:年輕代中第一個survivor已使用的占當(dāng)前容量百分比
S1:年輕代中第二個survivor已使用的占當(dāng)前容量百分比
E:年輕代中Eden已使用的占當(dāng)前容量百分比
O:old代已使用的占當(dāng)前容量百分比
P:perm代已使用的占當(dāng)前容量百分比
S0CMX:年輕代中第一個survivor的最大容量 (字節(jié))
S1CMX :年輕代中第二個survivor的最大容量 (字節(jié))
ECMX:年輕代中Eden的最大容量 (字節(jié))
DSS:當(dāng)前需要survivor的容量 (字節(jié))(Eden區(qū)已滿)
TT: 持有次數(shù)限制
MTT : 最大持有次數(shù)限制
20171208 補充
目前系統(tǒng)接入了 APM(Application Performance Management) 對整個系統(tǒng)的運行進(jìn)行監(jiān)控。監(jiān)控內(nèi)容包括但不限 JVM 相關(guān)內(nèi)容,非常值得參考。
APM 傳送問