1.概述
本文是《深入理解java虛擬機》(周志明著)3.6節的筆記整理,文章結構也與書上相同,講述的是幾條最普遍的內存分配策略。
2.對象優先在Eden分配
** 大多數情況下,對象在新生代Eden去中分配,(注:java堆中的新生代可分為Eden區和兩個Survivor區),當Eden區中沒有足夠的空間進行分配時,虛擬機將發起一次Minor GC。 **
Minor GC 和 Full GC的區別
- 新生代GC(Minor GC):指的是發生在新生代中的垃圾收集動作,java對象的創建和回收非常頻繁,所以Mnior GC非常頻繁,一般回收速度也比較快。
- 老年代GC(Major GC/Full FC):指發生在老年代中的GC,出現了Major GC經常會伴隨至少一次的Minor GC(並非絕對),Major GC的速度一般會比Minor GC慢10倍以上。
3.大對象直接進入老年代
大對象是指,需要大量連續內存空間的java對象(寫程序的時候應該避免“短命大對象”),經常出現大對象,容易導致內存還有不少空間時,就提前觸發垃圾收集以獲取足夠的連續空間來分給他們。 虛擬機提供-XX:PretenureSizeThreshold參數,令大於這個設置值的對象直接進入老年代,這么做為目的是為了避免在Eden以及兩個Survivor區之間發生大量的內存復制(新生代的垃圾收集算法采用復制算法)。
4.長期存活的對象將進入老年代
虛擬機給每個對象定義一個對象年齡(Age)的計數器,如果對象在Eden出生並經過第一次Minor GC后仍然存活,並且能被Survivor容納的話,將被移動到Survivor空間中,並且對象年齡設為1.其在Survivor中沒經歷一次Minior GC,Age就加1,當其Age增加到一定程度(默認15歲),就將其晉升到老年代。年齡閾值可以通過參數-XX:MxTenuringThreshold設置。
5.動態對象的年齡判定
為了能更好的適應不同程序的內存狀況,虛擬機不是永遠地要求對象的年齡必須達到MaxTenuringThreshold才能晉升老年代,**如果Survivor空間中相同年齡所有對象大小的總和大於Survivor空間的一半,年齡大於或者等於該年齡的對象就可以直接進入老年代。**
6.空間分配擔保
在發生Minor GC之前,虛擬機會先檢查老年代中最大可用連續空間是否大於新生代所有對象總空間,如果這個條件成立,那么Minor GC可以確保是安全的。如果不成立,則虛擬機會查看HandlePromotionFailure設置值是否允許擔保失敗。如果允許,那么會繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代對象的平均大小,如果大於將嘗試進行一次Minor GC。如果小於或者HandlePromotionFailure設置為不允許,那這時就改為一次Full GC。 分配擔保解釋: 新生代使用復制算法完成垃圾收集,為了節約內存Survivor的設置的比較小,當Minor GC后如果還有大量對象存活,超過了一個Survivor的內存空間,這時就需要老年代進行分配擔保,把Survivor中無法容納的對象直接進入老年代。若虛擬機檢查老年代中最大可用連續空間大於新生代所有對象總空間那么就能保證不需要發生Full GC,因為老年代的內存空間夠用。反之,如果老年代中最大可用連續空間小於新生代所有對象總空間就需要在嘗試Minor GC失敗后進行Full Gc或者直接Full GC。