這裡不是流水一樣的介紹功能怎麼用,就說說線上遇到的問題,我們通常怎麼排查,排查的幾種情況。
1.記憶體溢出,出現OutOfMemoryError,這個問題如何排查
2.CPU使用猛增,這個問題如何排查?
3.程序有死鎖,這個問題如何排查?
4.JVM參數調優
第一步:通過jmap -histo指令檢視系統記憶體使用情況
使用的指令:
jmap -histo -pid(程序id)
通過這個指令,我們可以看出目前哪個對象最消耗記憶體。
上面這個運作結果是我啟動了本地的一個項目,然後運作【jmap -histro 程序号】運作出來的結果,直 接去了其中的一部分。通過這裡我們可以看看大的執行個體對象中,有沒有我們自定義的執行個體對象。通過這 個可以排查出哪個執行個體對象引起的記憶體溢出。
除此之外, Total彙總資料可以看出目前一共有多少個對象,暫用了多大記憶體空間。這裡是有約860w個 對象,占用約923M的空間。
第二步:分析記憶體溢出,檢視堆空間占用情況
使用指令
jmap -heap -pid (程序id)
比如,我本地啟動了一個項目,想要檢視這個項目的記憶體占用情況
[root ~]# jmap -heap 15271
Attaching to process ID 15271, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.77-b03
using thread-local object allocation.
Garbage-First (G1) GC with 2 thread(s)
Heap Configuration:
MinHeapFreeRatio
MaxHeapFreeRatio
MaxHeapSize
NewSize
MaxNewSize
OldSize
NewRatio
SurvivorRatio
MetaspaceSize
= 40
= 70
= 536870912 (512.0MB)
= 1363144 (1.2999954223632812MB)
= 321912832 (307.0MB)
= 5452592 (5.1999969482421875MB)
= 2
= 8
= 134217728 (128.0MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize
G1HeapRegionSize
= 134217728 (128.0MB)
= 1048576 (1.0MB)
Heap Usage:
G1 Heap:
regions = 512
capacity = 536870912 (512.0MB)
used = 283115632 (270.00010681152344MB)
free = 253755280 (241.99989318847656MB)
52.73439586162567% used
G1 Young Generation:
Eden Space:
regions = 132
capacity = 305135616 (291.0MB)
used = 138412032 (132.0MB)
free = 166723584 (159.0MB)
45.36082474226804% used
Survivor Space:
regions = 32
capacity = 33554432 (32.0MB)
used = 33554432 (32.0MB)
free = 0 (0.0MB)
100.0% used
G1 Old Generation:
regions = 110
capacity = 198180864 (189.0MB)
used
free
= 111149168 (106.00010681152344MB)
= 87031696 (82.99989318847656MB)
56.08471259868965% used
48916 interned Strings occupying 5031568 bytes.
下面來看看參數的含義
堆空間配置資訊
Heap Configuration:
/**
* 空閑堆空間的最小百分比,計算公式為:HeapFreeRatio =
(CurrentFreeHeapSize/CurrentTotalHeapSize) * 100,值的區間為0 * 到100,預設值為
40。如果HeapFreeRatio < MinHeapFreeRatio,則需要進行堆擴容,擴容的時機應該在每次垃圾回收之 後。
*/
MinHeapFreeRatio = 40
/**
* 空閑堆空間的最大百分比,計算公式為:HeapFreeRatio =
(CurrentFreeHeapSize/CurrentTotalHeapSize) * 100,值的區間為0
* 到100,預設值為 70。如果HeapFreeRatio > MaxHeapFreeRatio,則需要進行堆縮容,縮容的 時機應該在每次垃圾回收之後
*/
MaxHeapFreeRatio = 70
/**JVM 堆空間允許的最大值*/
MaxHeapSize = 2065694720 (1970.0MB)
/** JVM 新生代堆空間的預設值*/
NewSize = 1363144 (1.2999954223632812MB)
/** JVM 新生代堆空間允許的最大值 */
MaxNewSize = 1239416832 (1182.0MB)
/** JVM 老年代堆空間的預設值 */
OldSize = 5452592 (5.1999969482421875MB)
/** 新生代 (2個Survivor區和Eden區 )
*與老年代 (不包括永久區) 的堆空間比值,表示新生代:
*老年 代=1:2
*/
NewRatio = 2
/** 兩個Survivor區和Eden區的堆空間比值為 8,表示 S0 : S1 :Eden = 1:1:8 */
SurvivorRatio
/** JVM 元空間的預設值 */ MetaspaceSize = 8
= 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
/** JVM 元空間允許的最大值 */
MaxMetaspaceSize = 17592186044415 MB
/** 在使用 G1 垃圾回收算法時,JVM 會将 Heap 空間分隔為若幹個 Region,
* 該參數用來指定每個 Region 空間的大小
*/
G1HeapRegionSize = 1048576 (1.0MB)
G1堆使用情況
G1 Heap:
regions = 512
capacity = 536870912 (512.0MB)
used = 283115632 (270.00010681152344MB)
free = 253755280 (241.99989318847656MB)
52.73439586162567% used
G1 的 Heap 使用情況,該 Heap 包含 512 個 Region,結合上文每個 RegionSize=1M,
是以
Capacity = Regions * RegionSize = 512 * 1M = 1970M,
已使用空間為270.00010681152344MB,
空閑空間為 241.99989318847656MB,
使用率為 52.73439586162567%。
G1年輕代Eden區使用情況
G1 Young Generation:
Eden Space:
regions = 132
capacity = 305135616 (291.0MB)
used = 138412032 (132.0MB)
free = 166723584 (159.0MB)
45.36082474226804% used
G1年輕代Survivor區使用情況
Survivor Space:
regions = 32
capacity = 33554432 (32.0MB)
used
free = 33554432 (32.0MB)
= 0 (0.0MB)
100.0% used
G1老年代使用情況
G1 Old Generation:
regions = 110
capacity = 198180864 (189.0MB)
used
free = 111149168 (106.00010681152344MB)
= 87031696 (82.99989318847656MB)
56.08471259868965% used
通過上面的指令,我們就能知道目前系統堆空間的使用情況了,到底是老年代有問題還是新生代有問 題。
我們可以通過Jstack找出占用cpu最高的線程的堆棧資訊,下面來一步一步分析。
第一步:運作代碼,使用top指令檢視cpu占用情況
第二步:使用top -p 指令檢視飙高程序
top -p 15271
[root~]# top -p 15271
top - 14:06:27 up 88 days, 4:29, 5 users, load average: 4.14, 2.32, 1.32
Tasks: 0 total, 0 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 90.2 us, 4.0 sy, 0.0 ni, 5.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB
Mem : 8009264 total, 1529888 free, 4388024 used, 2091352 buff/cache
KiB Swap: 8388604 total, 8388604 free, 0 used. 3194448 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
第三步:按H,擷取每個線程的記憶體情況
需要注意的是,這裡的H是大寫的H。
第四步:找到記憶體和cpu占用最高的線程tid
過上圖我們看到占用cpu資源最高的線程有兩個,線程号分别是4018362, 4018363。我們一第一個為 例說明,如何查詢這個線程是哪個線程,以及這個線程的什麼地方出現問題,導緻cpu飙高。
第五步:将線程tid轉化為十六進制
67187778是線程号為4013442的十六進制數。具體轉換可以網上查詢工具。
第六步:執行[ jstack 4018360 |grep -A 10 67187778] 查詢飙高線
程的堆棧資訊
接下來查詢飙高線程的堆棧資訊
jstack 4013440|grep -A 10 67190882
4013440:表示的是程序号
67187778: 表示的是線程号對應的十六進制數
通過這個方式可以查詢到這個線程對應的堆棧資訊
從這裡我們可以看出有問題的線程id是0x4cd0, 哪一句代碼有問題呢, Math類的22行。
第七步:檢視對應的堆棧資訊找出可能存在問題的代碼
上述方法定位問題已經很精确了,接下來就是區代碼裡排查為什麼會有問題了。
備注:上面的程序id可能沒有對應上,在測試的時候,需要寫對程序id和線程id
jvm調優通常使用的是Jstat指令
1. 垃圾回收統計 jstat -gc
jstat -gc 程序id
上面的參數分别是什麼意思呢?先識别參數的含義,然後根據參數進行分析
S0C: 第一個Survivor區的容量
S1C: 第二個Survivor區的容量
S0U: 第一個Survivor區已經使用的容量
S1U:第二個Survivor區已經使用的容量
EC: 新生代Eden區的容量
EU: 新生代Eden區已經使用的容量
OC: 老年代容量
OU:老年代已經使用的容量
MC: 方法區大小 (元空間)
MU: 方法區已經使用的大小
CCSC:壓縮指針占用空間
CCSU:壓縮指針已經使用的空間
YGC: YoungGC已經發生的次數
YGCT: 這一次YoungGC耗時
FGC: Full GC發生的次數
FGCT: Full GC耗時
GCT: 總的GC耗時,等于YGCT+FGCT
連續觀察GC變化的指令
jstat -gc 程序ID 間隔時間 列印次數
這樣就連續列印了10次gc的變化,每次隔一秒。
這個指令是對整體垃圾回收情況的統計,下面将會差分處理
2.堆記憶體統計
這個指令是列印堆記憶體的使用情況。
jstat -gccapacity 程序ID
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:目前新生代容量
S0C:第一個Survivor區大小
S1C:第二個Survivor區大小
EC:Eden區的大小
OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:目前老年代大小
OC: 目前老年代大小
MCMN: 最小中繼資料容量
MCMX:最大中繼資料容量
MC:目前中繼資料空間大小
CCSMN:最小壓縮類空間大小
CCSMX:最大壓縮類空間大小
CCSC:目前壓縮類空間大小
YGC:年輕代gc次數
FGC:老年代GC次數
3.新生代垃圾回收統計
jstat -gcnew 程序ID [ 間隔時間 列印次數]
S0C:第一個Survivor的大小
S1C:第二個Survivor的大小
S0U:第一個Survivor已使用大小
S1U:第二個Survivor已使用大小
TT: 對象在新生代存活的次數
MTT: 對象在新生代存活的最大次數
DSS: 期望的Survivor大小
EC:Eden區的大小
EU:Eden區的使用大小
YGC:年輕代垃圾回收次數
YGCT:年輕代垃圾回收消耗時間
4. 新生代記憶體統計
jstat -gcnewcapacity 程序ID
參數含義:
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:目前新生代容量
S0CMX:Survivor 1區最大大小
S0C:目前Survivor 1區大小
S1CMX:Survivor 2區最大大小
S1C:目前Survivor 2區大小
ECMX:最大Eden區大小
EC:目前Eden區大小
YGC:年輕代垃圾回收次數
FGC:老年代回收次數
5. 老年代垃圾回收統計
jstat -gcold 程序ID
MC:方法區大小
MU:方法區已使用大小
CCSC:壓縮指針類空間大小
CCSU:壓縮類空間已使用大小
OC:老年代大小
OU:老年代已使用大小
YGC:年輕代垃圾回收次數
FGC:老年代垃圾回收次數
FGCT:老年代垃圾回收消耗時間
GCT:垃圾回收消耗總時間,新生代+老年代
6. 老年代記憶體統計
jstat -gcoldcapacity 程序ID
7. 中繼資料空間統計
jstat -gcmetacapacity 程序ID
8.整體運作情況
jstat -gcutil 程序ID