1. 程式人生 > >記憶體分配與回收策略(五)

記憶體分配與回收策略(五)

回收策略:

  1. Minor GC
  2. Major GC/Full GC

Minor GC:發生在新生代的GC,發生非常頻繁,消耗時間短。

Major GC:發生在老年代GC,消耗時間一般為新生代GC的10倍,甚至更多(1000倍)。

Full GC:新生代+老年代 GC。一般情況MajorGC是由MinorGC觸發,所以MajorGC一般(也有一些收集器直接進行Major GC)會伴隨一次Minor GC,所以也寫成Major GC/Full GC。

記憶體分配:

1.物件優先在Eden分配:大多數情況下,物件在新生代Eden區分配。當Eden區沒有足夠空間進行分配時,虛擬機器將發起一次Minor GC。

2.大物件直接進入老年代:虛擬機器提供一個-XX:PretenureSizeThreshold引數,令大於這個設定值的物件直接在老年代分配。這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的記憶體複製。(PretenureSizeThreshold引數只對Serial和ParNew兩款收集器有效,Parallel Scavenge收集器不認識這個引數。)

3.長期存活的物件將進入老年代:虛擬機器給每個物件定義了一個物件年齡(Age)計數器。如果物件在Eden出生並經過第一次MinorGC後仍然存活,並且能被Survivor容納的話,將被移動到Survivor空間中,並且物件年齡設為1。物件在Survivor區中每“熬過”一次MinorGC,年齡就增加1歲,當年齡增加到一定程度(預設為15歲),就會被晉升到老年代中。物件晉升老年代的年齡閾值,可以通過引數:-XX:MaxTenuringThreshold設定。

4.動態年齡判斷:為了更好的適應不同程式的記憶體狀況,虛擬機器並不是永遠要求物件年齡必須達到了MaxTenuringThreshold才能晉升老年代,如果在Survivor空間中相同年齡所有物件大小總和大於Survivor空間的一半,年齡大於等於該年齡的物件就直接進入老年代,無需達MaxTenuringThreshold中要求的年齡。

5.空間分配擔保:在發生MinorGC之前,虛擬機器會先檢查老年代**最大可用連續空間是否大於新生代所有物件總空間,如果這個條件成立,那麼MinorGC可以確保是安全的。如果不成立,則虛擬機器會檢視HandlePromotionFailure設定值是否允許擔保失敗。如果允許,那麼會繼續檢查老年代最大可用連續空間是否大於歷次晉升到老年代物件的平均大小,如果大於,將嘗試進行一次MinorGC,儘管這次MinorGC是有風險的;如果小於,或者HandlePromotionFailure設定不允許“冒險”,那這時也要改為進行一次FullGC。

PS:冒險:因為新生代使用複製收集演算法,但是為了記憶體利用率,只使用其中一個Survivor空間作為輪換備份。如果當出現MinorGC後仍然有大量存活,就需要老年代進行分配擔保,前提是老年代本身還有容納這些物件的剩餘空間,一共有多少物件存活下來 在實際記憶體回收完成之前是無法明確知道的,所以只能取之前一次晉升到老年代物件容量的平均大小值作為經驗值,與老年代的剩餘空間進行比較,決定是否進行FullGC來讓老年代騰出更多空間。由於取平均值進行比較是一種動態概率的手段,也可能某次MinorGC存活物件突增,遠遠高於平均值,依然會導致擔保失敗(Handle Promotion Failure)。如果出現了HPF失敗,那就只能在失敗後重新發起一次FullGC。大部分情況下,HandlePromotionFailure開關是開啟的,避免FullGC過於頻繁。