天天看點

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

作者:玄明Hanko

#挑戰30天在頭條寫日記#

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

場景一、CPU過高

CPU占用過高排查思路:(查程序->查線程清單->查線程堆棧)

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step1:通過top指令查詢占用CPU情況

top            

p.s.shift+p(大寫的P-cpu排序) shift+m(大寫的M-記憶體排序)

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step2:通過程序pid,查詢對應的線程清單

top -Hp pid           
  • -H:顯示線程資訊
  • -p pid1,pid2,...:隻顯示指定程序的資訊
深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step3:線程id轉為十六進制

從step2中可以看到占用cpu較高的線程id,列印出十六進制

printf  '%x\n' id           
深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step4:通過jstack查出線程棧資訊

cpu過高主要是線程方面的問題,我們知道jvm中每個線程都配置設定了單獨的棧,我們可以通過jstack檢視線程棧情況。

jstack pid           

p.s.這裡的pid為程序id,也就是第一步top中的pid

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

對照着step3中占用cpu最高的線程十六進制值可以定位到線程的棧資訊。

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

上圖可以看到具體定位到了java的代碼,就可以具體分析一下這個java代碼為什麼會建立大量的線程占用大量的cpu。

除了java程式線程問題,cpu過高也可能是線程死鎖造成的,我們通過jstack也可以檢視線程死鎖的情況。

step5:通過jstack檢視情況死鎖情況

jstack -l pid           

-l:除了線程清單外,還顯示關于鎖的附加資訊

通過棧中的資訊可以定位到代碼中死鎖的代碼。

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step6:通過jstat檢視gc情況

除了以上的各種情況,還有一種就是java頻繁的gc也會造成cpu占用過高

jstat -gcutil pid 1000           

1000ms為重新整理資料的間隔時間

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

如果有頻繁的gc就可以分析堆資料中哪些對象建立的比較多,就可以具體分析了。

場景二、記憶體占用過高

排查思路: (查程序->jvm記憶體占用)

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step1:通過top指令查詢占用CPU情況

top            

p.s.shift+p(大寫的P-cpu排序) shift+m(大寫的M-記憶體排序)

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step2:通過程序pid檢視gc情況

jstat -gcutil pid 1000            
深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

以下是該指令的輸出結果說明:

  • S0:表示survivor space 0區域的使用情況,即第1個幸存區的使用情況。
  • S1:表示survivor space 1區域的使用情況,即第2個幸存區的使用情況。
  • E:表示eden space區域的使用情況,即新生代中Eden區的使用情況。
  • O:表示old space區域的使用情況,即老年代中的使用情況。
  • M:表示metaspace區域的使用情況,即元空間中的使用情況。
  • CCS:表示壓縮類空間的使用情況。如果JVM啟用了類資料共享(CDS)技術并且開啟了壓縮類指針(Compressed Class Pointer)選項,那麼就會存在一個稱為“壓縮類空間”的特殊區域,用于存放共享的類中繼資料資訊。
  • YGC:表示年輕代垃圾回收的次數。年輕代是JVM中記憶體配置設定的主要區域,垃圾回收在此區域較為頻繁。
  • YGCT:表示年輕代垃圾回收所花費的時間總和。通常情況下,年輕代垃圾回收所需時間不應過長,否則可能會導緻系統響應變慢或出現卡頓現象。
  • FGC:表示Full GC(全局垃圾回收)的次數。Full GC是對整個Java堆進行清理的垃圾回收過程,較為耗時。
  • FGCT:表示Full GC所花費的時間總和。Full GC的執行時間通常比年輕代垃圾回收要長得多,因為它需要處理整個Java堆。
  • GCT:表示所有垃圾回收所花費的時間總和,即YGCT和FGCT的總和。

以上各個區域的使用情況都會以百分比的形式進行顯示,即0.0%~100.0%之間。

例如,如果輸出結果為“40.00 20.00 60.00 70.00 100.00”,則表示:

  • survivor space 0的使用率為40.00%
  • survivor space 1的使用率為20.00%
  • eden space的使用率為60.00%
  • old space的使用率為70.00%
  • metaspace的使用率為100.00%

step3:通過jmap檢視堆情況

通過step2已經發現jvm中的資料過多,頻繁的ygc并且大量的資料都在老年代沒有回收,這樣就會表現出記憶體占用過高。下一步就是分析那些對象占用了記憶體。

jmap -histo pid           

jmap -histo指令可以用于輸出Java堆記憶體中各個對象類型及其數量的統計資訊。具體說明如下:

  • num 參數代表要分析的Java程序中的對象編号
  • instances:表示Java堆記憶體中對象的數量
  • bytes:表示Java堆記憶體中對象占用的總位元組數。
  • class name:表示Java堆記憶體中對象所屬類名。
深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

可以看到org.example.User建立的比較多。這相就可以具體分析一下代碼中哪些地方建立了User為什麼沒被回收。

與jmap -histo類似的指令:

#jmap -dump
jmap -dump:format=b,file=heapdump.hprof pid           
深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

jmap -dump指令可以用于生成Java程序的記憶體快照檔案(.hprof格式),以便進行後續的分析和調試。具體說明如下:

  • filepath:表示生成的記憶體快照檔案路徑。該檔案可以通過Java虛拟機診斷工具(例如VisualVM、Eclipse Memory Analyzer等)進行分析和調試。
  • pid:表示要生成記憶體快照的Java程序的程序ID。

導出的快照檔案可以通過jvisualvm或mat來檢視:

  • jvisualvm
深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧
  • mat

mat還比較智能,直接把存在問題的給你列出來

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

step4:jmap -heap jvm記憶體實際占用情況

除了以上記憶體占用情況,在java項目中還存在一種情況。比如我java項目沒有配置jvm參數都使用預設的配置,我伺服器64G記憶體。會發現用一段時間後java程序占用了8G記憶體。這時你可以使用指令看看java實際使用的記憶體情況,然後再調整jvm參數。

深度剖析JVM調優法則從兩大特性CPU記憶體出發輕松掌握調優實戰技巧

jmap -heap是一個用于擷取Java堆記憶體資訊的指令行工具,它可以輸出Java虛拟機中堆記憶體的使用情況和配置資訊。

=========================================

如果文章對你有幫助,不要忘記加個關注、點個贊!

繼續閱讀