jvm垃圾内存回收问题
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 | 0 | 100 | 100 | 98.75 | 584 | 13.28 | 1447 | 3699.659 | 3712.939 |
| ?0.00 | 0 | 100 | 100 | 98.75 | 584 | 13.28 | 1447 | 3699.659 | 3712.939 |
| ?0.00 | 0 | 100 | 100 | 98.75 | 584 | 13.28 | 1447 | 3699.659 | 3712.939 |
| ?0.00 | 0 | 100 | 100 | 98.75 | 584 | 13.28 | 1448 | 3702.135 | 3715.416 |
| ?0.00 | 0 | 100 | 100 | 98.75 | 584 | 13.28 | 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區內存占用 | 永久區最小 | 永久區最大 | 永久區當前 | 永久區內存占用 | 新生帶GC次數 | Full GC 次數 |
| NGCMN | NGCMX | NGC | S0C | S1C | EC | OGCMN | OGCMX | OGC | OC | PGCMN | PGCMX | PGC | PC | YGC | FGC |
| 21824 | 349504 | 64384 | 2112 | 3904 | 56448 | 43712 | 699072 | 178496 | 178496 | 16384 | 65536 | 35712 | 35712 | 146 | 9 |
| 21.3125 | 341.3125 | 62.875 | 2.0625 | 3.8125 | 55.125 | 42.6875 | 682.6875 | 174.3125 | 174.3125 | 16 | 64 | 34.875 | 34.875 |
我們的Eden區較小,這個可能會觸發JVM的一個BUG(1.6u18前的版本,我們的版本是:java version "1.6.0_37")正好在這個范圍內,具體信息查看:http://www.oschina.net/question/1092_24066
嘗試升級jdk版本或者調整JVM內存參數解決該問題。
轉載于:https://blog.51cto.com/zhangshaoxiong/1206281
總結
以上是生活随笔為你收集整理的jvm垃圾内存回收问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在linux下面安装MySQL5.6管理
- 下一篇: 集合objectjava_collect