天天看點

JDK自帶的調優工具

這裡不是流水一樣的介紹功能怎麼用,就說說線上遇到的問題,我們通常怎麼排查,排查的幾種情況。

1.記憶體溢出,出現OutOfMemoryError,這個問題如何排查

2.CPU使用猛增,這個問題如何排查?

3.程序有死鎖,這個問題如何排查?

4.JVM參數調優

第一步:通過jmap -histo指令檢視系統記憶體使用情況

使用的指令:

jmap -histo -pid(程序id)

JDK自帶的調優工具

通過這個指令,我們可以看出目前哪個對象最消耗記憶體。

上面這個運作結果是我啟動了本地的一個項目,然後運作【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。

JDK自帶的調優工具

第四步:找到記憶體和cpu占用最高的線程tid

過上圖我們看到占用cpu資源最高的線程有兩個,線程号分别是4018362, 4018363。我們一第一個為 例說明,如何查詢這個線程是哪個線程,以及這個線程的什麼地方出現問題,導緻cpu飙高。

第五步:将線程tid轉化為十六進制

67187778是線程号為4013442的十六進制數。具體轉換可以網上查詢工具。

第六步:執行[ jstack 4018360 |grep -A 10 67187778] 查詢飙高線

程的堆棧資訊

接下來查詢飙高線程的堆棧資訊

jstack 4013440|grep -A 10 67190882
 
4013440:表示的是程序号
67187778:   表示的是線程号對應的十六進制數           

通過這個方式可以查詢到這個線程對應的堆棧資訊

JDK自帶的調優工具

從這裡我們可以看出有問題的線程id是0x4cd0, 哪一句代碼有問題呢, Math類的22行。

第七步:檢視對應的堆棧資訊找出可能存在問題的代碼

上述方法定位問題已經很精确了,接下來就是區代碼裡排查為什麼會有問題了。

備注:上面的程序id可能沒有對應上,在測試的時候,需要寫對程序id和線程id

jvm調優通常使用的是Jstat指令

1. 垃圾回收統計 jstat -gc

jstat -gc 程序id           
JDK自帶的調優工具
上面的參數分别是什麼意思呢?先識别參數的含義,然後根據參數進行分析

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 間隔時間  列印次數           
JDK自帶的調優工具

這樣就連續列印了10次gc的變化,每次隔一秒。

這個指令是對整體垃圾回收情況的統計,下面将會差分處理

2.堆記憶體統計

這個指令是列印堆記憶體的使用情況。

jstat -gccapacity 程序ID           
JDK自帶的調優工具
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 [ 間隔時間  列印次數]           
JDK自帶的調優工具
S0C:第一個Survivor的大小
S1C:第二個Survivor的大小
S0U:第一個Survivor已使用大小
S1U:第二個Survivor已使用大小
TT: 對象在新生代存活的次數
MTT: 對象在新生代存活的最大次數
DSS: 期望的Survivor大小
EC:Eden區的大小
EU:Eden區的使用大小
YGC:年輕代垃圾回收次數
YGCT:年輕代垃圾回收消耗時間           

4. 新生代記憶體統計

jstat -gcnewcapacity 程序ID           
JDK自帶的調優工具
參數含義:

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           
JDK自帶的調優工具
MC:方法區大小
MU:方法區已使用大小
CCSC:壓縮指針類空間大小
CCSU:壓縮類空間已使用大小
OC:老年代大小
OU:老年代已使用大小
YGC:年輕代垃圾回收次數
FGC:老年代垃圾回收次數
FGCT:老年代垃圾回收消耗時間
GCT:垃圾回收消耗總時間,新生代+老年代           

6. 老年代記憶體統計

jstat -gcoldcapacity 程序ID           

7. 中繼資料空間統計

jstat -gcmetacapacity 程序ID           

8.整體運作情況

jstat -gcutil 程序ID           

繼續閱讀