Java服務(wù)器內(nèi)存過高&CPU過高問題排查
一、內(nèi)存過高
1、內(nèi)存過高一般有兩種情況:內(nèi)存溢出和內(nèi)存泄漏
(1)內(nèi)存溢出:程序分配的內(nèi)存超出物理機(jī)的內(nèi)存大小,導(dǎo)致無法繼續(xù)分配內(nèi)存,出現(xiàn)OOM報錯
(2)內(nèi)存泄漏:不再使用的對象一直占據(jù)著內(nèi)存不釋放,導(dǎo)致這塊內(nèi)存浪費(fèi)掉,久而久之,內(nèi)存泄漏的對象堆積起來,也會導(dǎo)致物理機(jī)的內(nèi)存被耗盡,出現(xiàn)OOM報錯
2、內(nèi)存過高的檢測辦法:通常我們的Java服務(wù)器部署在Linux機(jī)器上面,可以通過jvm自帶的命令進(jìn)行一些檢測
(1)查看對象的數(shù)目和占用內(nèi)存大小
①參數(shù)為Java程序的進(jìn)程號,將結(jié)果導(dǎo)出到指定目錄中,
- jmap -histo:live <進(jìn)程號> > <導(dǎo)出目錄+文件名>
②示例如下,可以看到程序中各個對象所占用內(nèi)存的情況,根據(jù)占用字節(jié)數(shù)大小降序顯示,這里只能看出哪些對象占用內(nèi)存高,但是還不能具體定位到問題代碼,需要進(jìn)一步排查
③一些特殊的標(biāo)識的含義
- [C 表示char[],一般與String對象相關(guān),因?yàn)镾tring其實(shí)就是基于char數(shù)組實(shí)現(xiàn)的
- [S 表示short[]
- [I 表示int[]
- [B 表示byte[]
- [II 表示int[][]
- num #instances #bytes class name
- ----------------------------------------------
- 1: 585152 75635896 [C
- 2: 66541 71446496 [B
- 3: 1141734 36535488 java.util.HashMap$Entry
- 4: 176622 26086840 <constMethodKlass>
- 5: 176622 24034208 <methodKlass>
- 6: 17717 19584560 <constantPoolKlass>
- 7: 174454 18375128 [Ljava.util.HashMap$Entry;
- 8: 571222 13709328 java.lang.String
- 9: 832783 13324528 java.lang.Integer
- 10: 17717 13198840 <instanceKlassKlass>
- 11: 15092 11237440 <constantPoolCacheKlass>
- 12: 46779 10429728 [I
- 13: 191501 7660040 java.util.LinkedHashMap$Entry
- 14: 12599 6567592 <methodDataKlass>
- 15: 113526 6357456 java.util.HashMap
- 16: 197998 6335936 java.util.Hashtable$Entry
(2)如果需要進(jìn)一步定位問題代碼,那么就需要把Java程序的內(nèi)存鏡像導(dǎo)出,再具體分析了,通過如下命令導(dǎo)出程序的內(nèi)存鏡像
- jmap -dump:format=b,file=<導(dǎo)出目錄+文件名> <進(jìn)程號>
(3)下載Memory Analyzer工具來分析內(nèi)存鏡像
- http://www.eclipse.org/mat/
(4)打開軟件后,F(xiàn)ile-->Open Heap Dump...,打開剛才導(dǎo)出的鏡像文件,選擇Leak Suspects Report,F(xiàn)inish,進(jìn)入分析頁面
- Histogram:列表展示出內(nèi)存中的對象數(shù)目和占用內(nèi)存大小
- Dominator Tree:列表展示出程序中每個線程中的對象數(shù)目和占用內(nèi)存大小
- Top Consumers:圖表展示出每個線程的對象數(shù)目和占用內(nèi)存大小
- Top Components:圖表展示出內(nèi)存中的對象數(shù)目和占用內(nèi)存大小
- Leak Suspects:這個是最常用的,會自動檢測分析內(nèi)存異常的原因
右鍵對象-->show objects by class可以查看對象的具體情況
by incomming reference:顯示引用該對象/線程的其他對象
by outgoing reference:顯示當(dāng)前對象/線程引用的其他對象

(5)點(diǎn)擊Leak Suspects,程序會分析出可能存在內(nèi)存問題的地方,繼續(xù)點(diǎn)擊Detail可以看到具體有哪些對象和線程,接下來就要根據(jù)具體情況具體分析了
二、CPU過高
1、當(dāng)程序發(fā)現(xiàn)CPU過高的情況時,可以使用Windows系統(tǒng)的Process Explorer工具來找到CPU高消耗的線程,所以需要在Windows機(jī)器上面搭建好服務(wù)器的測試環(huán)境,盡量模擬出線上CPU飆升的情況
2、模擬好環(huán)境后,通過任務(wù)管理器,在進(jìn)程一欄中找到Java程序的進(jìn)程號

3、下載Process Explorer工具
- https://docs.microsoft.com/zh-cn/sysinternals/downloads/process-explorer
4、打開工具后,根據(jù)剛才的進(jìn)程號找到進(jìn)程

5、然后右鍵-->Properties,再選擇Threads選項卡,點(diǎn)進(jìn)CPU排序,可以找到消耗CPU最多的那個線程

6、使用科學(xué)計算器,將十進(jìn)制的線程號轉(zhuǎn)成十六進(jìn)制,比如493620-->78834

7、到此已經(jīng)拿到了可能出問題的進(jìn)程號和線程號,接下來使用jvm內(nèi)置的命令來導(dǎo)出Java的堆棧信息
- jstack -l <進(jìn)程號> > <導(dǎo)出目錄+文件名>
8、打開導(dǎo)出的堆棧信息,并全文搜索剛剛拿到的十六進(jìn)制的線程號,就可以找到出問題的代碼具體位置了
作者:未分配的為服務(wù)