01 前言
版權聲明:本文爲CSDN博主「Μr.ηobοdy」的原創文章
原文鏈接:https://blog.csdn.net/chenlixiao007/article/details/105999034
cpu是時分(time division)的,操作系統裏有很多線程,每個線程的運行時間由cpu決定,cpu會分給每個線程一個時間片,時間片是一個很短的時間長度,如果在時間片內,線程一直佔有,則是100%;我們應該意識到,cpu運行速度很快(主頻非常高),除非密集型耗費cpu的運算,其它類型任務都會在小於時間片的時間內結束。
java cpu100%的排查步驟,基本都是一模一樣的,只是命令稍有區別!步驟如下:
- 查找消耗cpu最高的進程PID
- 根據PID查出消耗cpu最高的線程號
- 根據線程號查出對應的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。