JVM 常見線上問題 → CPU 100%、記憶體洩露 問題排查

青石路發表於2020-10-09

開心一刻

明明是個小 bug,但就是死活修不好,我特麼心態崩了......

前言

  後文會從 Windows、Linux 兩個系統來做示例展示,有人會有疑問了:為什麼要說 Windows 版的 ? 目前市面上還是有很多 Windows 伺服器的,應用於傳統行業、政府結構、醫療行業 等等;兩個系統下的情況都演示下,有備無患

  後文中用到了兩個工具:Processor ExplorerMAT,它們是什麼,有什麼用,怎麼用,本文不做介紹,不知道的小夥伴最好先去做下功課

cpu 100%

  下面的示例中, cpu 的佔有率沒到 100%,只是比較高,但是排查方式是一樣的,希望大家不要鑽牛角尖

  Windows

    1、找到 cpu 佔有率最高的 java 程式號

      

      PID: 20260 

    2、根據程式號找到 cpu 佔有率最高的執行緒號

      雙擊剛剛找到的 java 程式

      

      執行緒號: 15900 ,轉成十六進位制: 3e1c 

    3、利用 jstack 生成虛擬機器中所有執行緒的快照

      命令: jstack -l {pid} > {path} 

      

      檔案路徑: D:\20260.stack 

    4、執行緒快照分析

      我們先瀏覽下快照內容

      

      內容還算比較簡潔,執行緒快照格式都是統一的,我們以一個執行緒快照簡單說明下

       "main" #1 prio=5 os_prio=0 tid=0x0000000002792800 nid=0x3e1c runnable [0x00000000025cf000] 

      

      我們前面找到佔 cpu 最高的執行緒號: 15900 ,十六進位制: 3e1c ,用 3e1c  去快照檔案裡面搜一下

      

      自此,找到問題

      

  Linux

    排查方式與 Windows 版一樣,只是命令有些區別

    1、找到 cpu 佔有率最高的 java 程式號

      使用命令: top -c 顯示執行中的程式列表資訊, shift + p 使列表按 cpu 使用率排序顯示

      

       PID = 2227 的程式,cpu 使用率最高

    2、根據程式號找到 cpu 佔有率最高的執行緒號

      使用命令: top -Hp {pid} ,同樣 shift + p 可按 cpu 使用率對執行緒列表進行排序

      

       PID = 2228 的執行緒消耗 cpu 最高,十進位制的 2228 轉成十六進位制 8b4 

    3、利用 jstack 生成虛擬機器中所有執行緒的快照

      

    4、執行緒快照分析

      分析方式與 Windows 版一致,我們可以把 2227.stack 下載到本地進行分析,也可直接在 Linux 上分析

      在 Linux 上分析,命令: cat 2227.stack |grep '8b4' -C 5 

      

      至此定位到問題

      

    不管是在 Windows 下,還是在 Linux 下,排查套路都是一樣的

    

記憶體洩露

  同樣的,Windows、Linux 各展示一個示例

  Windows

    1、找到記憶體佔有率最高的程式號 PID

      

      第一眼看上去, idea 記憶體佔有率最高,因為我是以 idea 啟動的 java 程式;idea 程式我們無需關注,我們找到記憶體佔有率最高的 java 的 PID: 10824 

    2、利用  jmap 生成堆轉儲快照

      命令: jmap -dump:format=b,file={path} {pid} 

      

      dump 檔案路徑: D:\heapdump_108244.hprof 

    3、利用 MAT 分析 dump 檔案

      MAT:Memory Analyzer Tool,是針對 java 的記憶體分析工具;下載地址:

      

      選擇對應的版本,下載後直接解壓;預設情況下,mat 最大記憶體是 1024m ,而我們的 dump 檔案往往大於 1024m,所以我們需要調整,在 mat 的 home 目錄下找到 MemoryAnalyzer.ini ,將 -Xmx1024m 修改成大於 dump 大小的空間, 我把它改成了 -Xmx4096m 

      接著我們就可以將 dump 檔案匯入 mat 中,開始 dump 檔案的解析

      

      解析是個比較漫長的過程,我們需要耐心等待

      

      解析完成後,我們可以看到如下概況介面

      

      各個視窗的各個細節就不做詳細介紹了,有興趣的可自行去查閱資料;我們來看看幾個圖:餅狀圖、直方圖、支配樹、可疑的記憶體洩露報告

      餅狀圖

        

        可以看出, com.lee.schedule.Schedule 物件持有 1G 記憶體,肯定有問題

      直方圖

        

        我們看下 Person 定義

JVM 常見線上問題 → CPU 100%、記憶體洩露 問題排查
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Person {

    private String name;
    private Integer age;

}
View Code

        可想而知,上圖示記的幾項都與 Person 有關

      支配樹

        

        這就非常直觀了,Schedule 中的 ArrayList 佔了 99.04% 的大小

      可疑的記憶體洩露報告

        

      通過這些資料,相信大家也能找到問題所在了

      

  Linux

    排查方式與 Windows 一樣,只是有稍許的命令區別

    1、找到記憶體佔有率最高的程式號

      使用命令: top -c 顯示執行中的程式列表資訊, shift + m 按記憶體使用率進行排序

      

      程式號: 2527  

    2、利用 jmap 生成堆轉儲快照

      命令: jmap -dump:format=b,file={path} {pid} 

      

      堆轉儲快照檔案路徑: /opt/heapdump_2527.hprof 

    3、利用 MAT 分析堆轉儲快照

      將 heapdump_2448.phrof 下載到本地,利用 MAT 進行分析;分析過程與 Windows 版完全一致

      

      自此,定位到問題

    Windows 下與 Linux 下,排查流程是一樣的

    

總結

  JVM 常用命令

    jps:列出正在執行的虛擬機器程式

    jstat:監視虛擬機器各種執行狀態資訊,可以顯示虛擬機器程式中的類裝載、記憶體、垃圾收集、JIT編譯等執行資料

    jinfo:實時檢視和調整虛擬機器各項引數

    jmap:生成堆轉儲快照,也可以查詢 finalize 執行佇列、Java 堆和永久代的詳細資訊

    jstack:生成虛擬機器當前時刻的執行緒快照

    jhat:虛擬機器堆轉儲快照分析工具

      與 jmap 搭配使用,分析 jmap 生成的堆轉儲快照,與 MAT 的作用類似

  排查步驟

    1、先找到對應的程式: PID 

    2、生成執行緒快照 stack (或堆轉儲快照: hprof )

    3、分析快照(或堆轉儲快照),定位問題

  記憶體洩露、記憶體溢位和 CPU 100% 關係

     

  常用 JVM 效能檢測工具

    Eclipse Memory Analyer、JProfile、JProbe Profiler、JVisualVM、JConsole、Plumbr

參考

  一次完整的JVM堆外記憶體洩漏故障排查記錄

  【原創】談談線上CPU100%排查套路

  緊急修復一次線上商城系統高併發優化實戰

  面試官:如果你們的系統 CPU 突然飆升且 GC 頻繁,如何排查?

  記一次公司JVM堆溢位抽絲剝繭定位的過程

  MAT:一次線上記憶體洩漏排查

  JVM探祕:MAT分析記憶體溢位

相關文章