CrashReport系統在遊戲内測當天出現了異常情況JVM僵死,通過top -p <PID> -H 結合jstack(jstack -m -l pid)檢視,發現是VM Thread線程CPU占用100%,線程ID好為18540,線程資訊如下:
----------------- 18540 -----------------
0xb7904280 _ZN9MarkSweep12follow_stackEv + 0x30
0xb79b0637 _ZN11PSMarkSweep17mark_sweep_phase1Eb + 0xe7
0xb79af737 _ZN11PSMarkSweep16invoke_no_policyEb + 0x3c7
0xb79ba0ae _ZN10PSScavenge6invokeEv + 0x12e
0xb797f999 _ZN20ParallelScavengeHeap19failed_mem_allocateEjb + 0x49
0xb7ab191a _ZN29VM_ParallelGCFailedAllocation4doitEv + 0x5a
0xb7ac0096 _ZN12VM_Operation8evaluateEv + 0x46
0xb7abf523 _ZN8VMThread18evaluate_operationEP12VM_Operation + 0x83
0xb7abf794 _ZN8VMThread4loopEv + 0x194
0xb7abf280 _ZN8VMThread3runEv + 0x80
0xb796d64e _Z10java_startP6Thread + 0x14e
0x0056849b start_thread + 0xcb
Parallel GC 是JVM的垃圾回收線程( ParallelGC垃圾回收方式的特點是在New區開啟多線程回收)
既然是垃圾回收線程CPU占用100%,那麼說明我們的應用的JVM記憶體使用有問題,借助jstat檢視JVM的記憶體資訊如下:
jstat -gcutil pid 5000 #這裡是說每隔5000毫秒列印異常JVM記憶體資訊
存活區0
存活區1
伊甸區
Old區
永久區
新生帶GC次數
新生帶GC時間
Full GC次數
Full GC時間
GC的總時間
S0
S1
E
O
P
YGC
YGCT
FGC
FGCT
GCT
0.00
100
98.75
584
13.28
1447
3699.659
3712.939
1448
3702.135
3715.416
存活區0和存活區1的記憶體占用都是0%,伊甸區使用100%,Old區使用也是100%,Full GC的次數達到1448(3個小時内,差不多9s做一次Full GC,每次Full GC花費2.56s)
也就是說我們的應用頻繁的在做Full GC,而且Full GC消耗的時間也比較長,應用在做Full GC是整個應用是會阻塞的,是以在這種情況下我們的應用幾乎是不可用的。
什麼情況下會引發Full GC呢?參考下圖:
Old區記憶體不夠是JVM會觸發Full GC,由于Old區一直是滿的,是以會頻繁觸發Full GC,但是這個頻度也不高,應該不至于導緻CPU使用100%,我們用的是Parallel GC(并行GC),并行GC是說在新生帶會采取多線程來進行垃圾回收,由于我們Eden區也是滿的,是以GC的線程會CPU占用100%。
怎麼檢視我們的JVM每個區的記憶體大小情況呢?用jstat -gccapacity <PID>可以得到結果如下:
新生帶最小
新生帶最大
新生帶目前
存活區
老年帶最小
老年帶最大
老年帶目前
Old區記憶體占用
永久區最小
永久區最大
永久區目前
永久區記憶體占用
Full GC 次數
NGCMN
NGCMX
NGC
S0C
S1C
EC
OGCMN
OGCMX
OGC
OC
PGCMN
PGCMX
PGC
PC
21824
349504
64384
2112
3904
56448
43712
699072
178496
16384
65536
35712
146
9
21.3125
341.3125
62.875
2.0625
3.8125
55.125
42.6875
682.6875
174.3125
16
64
34.875
我們的Eden區較小,這個可能會觸發JVM的一個BUG(1.6u18前的版本,我們的版本是:java version "1.6.0_37")正好在這個範圍内,具體資訊檢視:http://www.oschina.net/question/1092_24066
嘗試更新jdk版本或者調整JVM記憶體參數解決該問題。