【轉載】JVM系列二:GC策略&記憶體申請、物件衰老
JVM裡的GC(Garbage Collection)的演算法有很多種,如標記清除收集器,壓縮收集器,分代收集器等等,詳見HotSpot VM GC 的種類
現在比較常用的是分代收集(generational collection,也是SUN VM使用的,J2SE1.2之後引入),即將記憶體分為幾個區域,將不同生命週期的物件放在不同區域裡:young generation,tenured generation和permanet generation。絕大部分的objec被分配在young generation(生命週期短),並且大部分的object在這裡die。當young generation滿了之後,將引發minor collection(YGC)。在minor collection後存活的object會被移動到tenured generation(
young generation有eden、2個survivor 區域組成。其中一個survivor區域一直是空的,是eden區域和另一個survivor區域在下一次copy collection後活著的objecy的目的地。object在survivo區域被複制直到轉移到tenured區。
我們要儘量減少 Full gc 的次數(tenured generation 一般比較大,收集的時間較長,頻繁的Full gc會導致應用的效能收到嚴重的影響)。
堆記憶體GC
JVM(採用分代回收的策略),用較高的頻率對年輕的物件(young generation)進行YGC,而對老物件(tenured generation)較少(tenured generation 滿了後才進行)進行Full GC。這樣就不需要每次GC都將記憶體中所有物件都檢查一遍。
非堆記憶體不GC
GC不會在主程式執行期對PermGen Space進行清理,所以如果你的應用中有很多CLASS(特別是動態生成類,當然permgen space存放的內容不僅限於類)的話,就很可能出現PermGen Space錯誤。
記憶體申請、物件衰老過程
一、記憶體申請過程
- JVM會試圖為相關Java物件在Eden中初始化一塊記憶體區域;
- 當Eden空間足夠時,記憶體申請結束。否則到下一步;
- JVM試圖釋放在Eden中所有不活躍的物件(minor collection),釋放後若Eden空間仍然不足以放入新物件,則試圖將部分Eden中活躍物件放入Survivor區;
- Survivor區被用來作為Eden及old的中間交換區域,當OLD區空間足夠時,Survivor區的物件會被移到Old區,否則會被保留在Survivor區;
- 當old區空間不夠時,JVM會在old區進行major collection;
- 完全垃圾收集後,若Survivor及old區仍然無法存放從Eden複製過來的部分物件,導致JVM無法在Eden區為新物件建立記憶體區域,則出現"Out of memory錯誤";
二、物件衰老過程
- 新建立的物件的記憶體都分配自eden。Minor collection的過程就是將eden和在用survivor space中的活物件copy到空閒survivor space中。物件在young generation裡經歷了一定次數(可以通過引數配置)的minor collection後,就會被移到old generation中,稱為tenuring。
- GC觸發條件
GC型別 觸發條件 觸發時發生了什麼 注意 檢視方式 YGC eden空間不足 清空Eden+from survivor中所有no ref的物件佔用的記憶體
將eden+from sur中所有存活的物件copy到to sur中
一些物件將晉升到old中:
to sur放不下的
存活次數超過turning threshold中的
重新計算tenuring threshold(serial parallel GC會觸發此項)重新調整Eden 和from的大小(parallel GC會觸發此項)
全過程暫停應用
是否為多執行緒處理由具體的GC決定jstat –gcutil
gc logFGC old空間不足
perm空間不足
顯示呼叫System.GC, RMI等的定時觸發
YGC時的悲觀策略
dump live的記憶體資訊時(jmap –dump:live)清空heap中no ref的物件
permgen中已經被解除安裝的classloader中載入的class資訊
如配置了CollectGenOFirst,則先觸發YGC(針對serial GC)
如配置了ScavengeBeforeFullGC,則先觸發YGC(針對serial GC)全過程暫停應用
是否為多執行緒處理由具體的GC決定
是否壓縮需要看配置的具體GCjstat –gcutil
gc log
參考: