1. 程式人生 > >一個大物件引起的血案,GC的踩坑實錄

一個大物件引起的血案,GC的踩坑實錄

踩過GC的幾個坑

1, 記憶體不夠用,JVM用到SWAP

如果每次GC時間不合理時,如: FGC=10,FGCT=1, 基本可以肯定是用到了SWAP記憶體區了 (當然也和你記憶體大小有關, 指一般系統記憶體在8G附近)

2, 用到大物件,導致頻繁FGC( FULLGC和 Major GC 對效能都有嚴重影響)

看很多資料上說是60%觸發Major GC, 但經測試發現, 在OU到了50%時開始不斷觸發Major GC

4,YGC變動越來越久, 如用到了string.intern()方法. (比如在 fastjson 中有用到), 

原因: string.intern() 往常量池加如資料。 而ROOT GC時, 需要掃描所有常量作為根節點, 當常量池越大量增加時,掃描的資料時間增加

5,GC裡面出現有

Concurrent mode failed

原因:由於GC在CMS時,往OU區放入物件,然後不可用。 

發現大量這種現象,

1,增加OLD區的記憶體壓縮引數, UseCMSCompactAtFullCollection 或 CMSFullGCsBeforeCompaction

2, 建議調大年輕代記憶體調大,或增加OLD區的回收頻率

Prommotion failed 

1. 年輕代物件晉升失敗, 當啟用了擔保分配,每次晉升會檢查年老代的記憶體是否夠大於年輕代平均晉升物件的大小,如果小於將會進行FULLGC,日誌會顯示Prommotion faile引起fullGC

2, JDK6後預設都開啟了擔保分配

再解釋下GC的幾個名詞

有幾個誤區:

FULL GC , Major GC , Minor GC

Minor GC 就是年輕代清理,這個好理解

FULL GC 指整個永久代(或G1的Metaspace代)的和堆記憶體 ,堆外記憶體一起清理.  在GC日誌裡的FULL GC指的是這個

Major GC 年老代的清理, 在jstat -gc 裡的FGC只是指這個,只是年老代的GC而已

誤區:jstat 的FGC, 它統計的僅僅是STW的次數,即 兩個init-mark和 remark的階段

問題:

引起FULL GC的原因有哪些呢?

1、System.gc()方法的呼叫 
2、老年代代空間不足 
3、永生區空間不足 
4、CMS GC時出現,如GC日誌中找到promotion failed(晉升失敗)和concurrent mode failure(回收時有物件要分配) 
5、統計得到的Minor GC晉升到舊生代的平均大小大於老年代的剩餘空間 
6、空間碎片太多,堆中分配很大的物件(如果如此,建議每次FULLGC後開啟壓縮)

如何檢視GC 發生的原因呢?

目前能想到的,最簡單是 jstat -gccause

持續更新留言問題,解答疑問

歡迎關注我的公眾號,專注重現各種線上的BUG

 或搜 “包子的實驗室”