程式碼介紹:
jdk提供的工具:
1、在Linux中啟動專案:java -cp ref-jvm.jar -XX:+PrintGC -Xms200M -Xmx200M ex13.FullGCProblem
2、top命令,實時顯示程序CPU百分比和記憶體使用情況:可以發現程序7498 佔用CPU比較高
等待一段時間:發現CPU使用率在逐漸增加
jinfo:顯示JVM引數設定資訊
jmap -heap 7498 :可以檢視記憶體使用情況
在不進行任何垃圾回收器指定情況的比例1:1:1
一段時間後 CPU佔比很高了
top -p 7498:單獨顯示7498程序佔比CPU
在監控介面輸入H,獲取當前程序下的所有執行緒資訊
jstack 7498:輸出執行緒資訊,nid為16進位制
將7500/7501換算成16進位制1D4C/1D4D,在介面中查詢,問題定位到CPU100%是瘋狂的垃圾回收的執行緒佔據的
jstat -gc 7498 2000 10:兩秒鐘重新整理一次GC資訊,一共查詢10次
各個欄位的含義如下:
不夠直觀,換個方式輸出:jstat -gc 7498 5000 20 | awk '{print $13,$14,$15,$16,$17}'
可以發現Full GC在增加,,說明記憶體不夠了
jmap -heap 7498,檢視堆記憶體情況,發現老年代使用率很大了,可能發生了記憶體洩漏
現在我們定位為是記憶體問題,CPU100%只是它的體現
jmap -histo 7498 | head -20:顯示堆空間對應7498程序對應物件佔用大小
問題總結(找到問題)
一般來說,前面那幾行,就可以看出,到底是哪些物件佔用了記憶體,這些物件回收不掉,導致了Full GC 裡面還有OOM
任務數多於執行緒數,那麼任務會進入阻塞佇列,就是一個佇列,因為程式碼中任務數一直多於執行緒數,所以每0.1s,就會有50個任務進入阻塞物件,50個任務底下有物件,至少物件送進去了,但是沒執行,所以導致物件一直都在,同時還回收不了。
為什麼回收不了,Executor是一個GCRoots,所以堆中,就會有60多萬個物件,阻塞佇列中60多萬個任務,futureTask,並且這些物件還回收不了。
總結
在JVM出現效能問題的時候(表現上是CPU100%,記憶體一直佔用)
1、出現CPU100%,要從兩個角度出發,一個有可能是業務執行緒瘋狂執行,比如說死迴圈,還有就是GC執行緒在瘋狂的回收,因為在JVM中垃圾回收器主流也是多執行緒的,所以很容易導致CPU100%;
2、在遇到記憶體溢位的問題的時候,一般情況下我們要檢視系統哪些物件佔用比較多,在實際業務程式碼中,找到對應的物件,分析對應的類,找到為啥這些物件不能回收的原因,就是透過可達性分析演算法,JVM的記憶體區域,還有就是垃圾回收器的基礎。