CPU100% 問題排查

01 前言

版權聲明:本文爲CSDN博主「Μr.ηobοdy」的原創文章
原文鏈接:https://blog.csdn.net/chenlixiao007/article/details/105999034

cpu是時分(time division)的,操作系統裏有很多線程,每個線程的運行時間由cpu決定,cpu會分給每個線程一個時間片,時間片是一個很短的時間長度,如果在時間片內,線程一直佔有,則是100%;我們應該意識到,cpu運行速度很快(主頻非常高),除非密集型耗費cpu的運算,其它類型任務都會在小於時間片的時間內結束。

java cpu100%的排查步驟,基本都是一模一樣的,只是命令稍有區別!步驟如下:

  1. 查找消耗cpu最高的進程PID
  2. 根據PID查出消耗cpu最高的線程號
  3. 根據線程號查出對應的java線程,進行處理。

02 Demo模擬

構造一個請求接口,模擬無限產生Person實例。
並進行接口調用:http://172.20.200.250:9563/demoService/demo/test?justDo=true

@RestController
@RequestMapping("demo")
public class DemoController {
    
    @GetMapping("test")
    public boolean test(@RequestParam boolean justDo) {

        List<Person> persons = new ArrayList<>();
        
        int i = 1;
        if (justDo) {
            while (true) {
                persons.add(new Person("張三", i));
                System.out.println(persons.size());
            }
        }
        return justDo;
    }
}

03 排查過程

1.使用top命令找出cpu佔用最高的進程
在這裏插入圖片描述
2.使用ps -ef | grep java或者jps命令查看cpu佔用高的進程是否爲java進程:
在這裏插入圖片描述
在這裏插入圖片描述
3.使用top -H -p pid命令查詢此進程的所有線程情況,發現主要有三個線程(PID爲29871 29872 29873)佔用cup高。-H表示以線程的維度展示,默認以進程維度展示。
在這裏插入圖片描述
4.使用命令jstack pid > pid.tdump將此進程的線程棧導出到文件並使用cat命令進行查看,pid.tdump文件後綴名隨意,通常以tdump結尾。

jstack 29869 > 29869.tdump
cat 29869.tdump

5.將前一步驟查出的3個線程PID從十進制轉爲十六進制,因爲java線程棧文件中的線程id是十六進制。對應分別爲29871 -> 0x74af,,29872 -> 0x74b0,29873 -> 0x74b1。發現此3個線程中有2個爲gc線程和1個工作線程。gc線程忙碌表示內存不夠用了,要進行內存回收,可能是java內存回收不了,導致一直gc。
在這裏插入圖片描述
6.使用jstat -gcutil pid命令查看進程的堆情況,發現年輕代中Eden(伊甸園)和old代已使用的佔當前容量百分比很高,並且GC頻繁。
在這裏插入圖片描述

名字 解析
S0 年輕代中第一個survivor(倖存區)已使用的佔當前容量百分比
S1 年輕代中第二個survivor(倖存區)已使用的佔當前容量百分比
E 年輕代中Eden(伊甸園)已使用的佔當前容量百分比
O old代已使用的佔當前容量百分比
M 元數據區使用比例
CCS 壓縮使用比例
YGC 從應用程序啓動到採樣時年輕代中gc次數
YGCT 從應用程序啓動到採樣時年輕代中gc所用時間(s)
FGC 從應用程序啓動到採樣時old代(全gc)gc次數
FGCT 從應用程序啓動到採樣時old代(全gc)gc所用時間(s)
GCT 從應用程序啓動到採樣時gc用的總時間(s)

7.使用jmap -dump:live,format=b,file=pid.hprof pid命令導出堆文件,只導出live的對象。文件後綴名可以是任意的,因爲它也是二進制的,不過通常以hprof結尾。
在這裏插入圖片描述
8.使用JAVA_HOME/bin/jvisualvm.exe工具分析快照。載入快照(文件----->載入—>文件類型(堆)):
在這裏插入圖片描述
選擇類列表,按照大小排序,找出佔用內存最大的類別,發現是Person類。
在這裏插入圖片描述
至此,問題找到原因,原來是在死循環中,不斷生產Person實例,並且無法回收,不僅工作線程一直佔用cpu,而且導致gc線程忙碌進行回收內存,但是回收不了,最後導致內存不足java.lang.OutOfMemoryError
在這裏插入圖片描述
java的bin目錄下有很多JVM性能調優監控工具jps、jstack、jmap、jhat、jstat、hprof。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章