現代虛擬機一般使用的內存回收策略是分代收集,即把對象分為兩代,新生代使用復制算法回收內存,老年代使用標志-整理算方法回收內存。但是有時候新生代對象存活率較高,導致有大對象分配時內存不足,虛擬機也會采用擔保機制是大對象進入老年代。
什么時候發生內存回收
大多數情況下,對象在新生代Eden區分配,當Eden區沒有足夠的空間進行分配時,虛擬機將發起一次Minor GC。同理,當老年代沒有足夠的空間時也會發起一次Full GC/Major GC
內存擔保機制
現代虛擬機把新生代分為三個區域,一個Eden區域,兩個Survivor區域,Eden區域與Survivor區域的比例大小是8:1,虛擬機在Minor GC時在新生代采用復制算法,將存活對象復制到一個Survivor上面,如果Survivor空間不夠用時,就需要老年代進行分配擔保。
在發生Minor GC之前虛擬機會先檢查老年代最大可用的連續空間是否大於新生代對象的總空間。如果這個條件成立,那么Minor GC可以確保是安全的。如果不成立,虛擬機會查看HandlePromotionFailure設置值是否允許擔保失敗。如果允許,虛擬機會繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代的平均年齡(因為事先不知道存活對象的內存空間,所以取了平均值)。若果大於,虛擬機會嘗試進行一次Minor GC,但是這次Minor GC存在風險。如果小於,或者HandlePromotionFailure不允許擔保,那這次也要改為Full GC
大對象直接進入老年代
大對象是指需要大量連續內存空間的對象,例如很長的字符串以及數組。
虛擬機設置了一個-XX:PretenureSizeThreshold參數,令大於這個設置的對象直接在老年代分配。目的就是為了防止大對象在Eden空間和Survivor空間來回大量復制。
長期存活的對象進入老年代
虛擬機給每個對象定義了一個對象年齡(Age)計數器,如果對象在Eden區出生並經過第一次Mintor GC后仍然存活,並且能被Survivor接納,並被移動到Survivor空間上,那么該對象年齡將被設置為1。對象在Survivor區中每熬過一次Minor GC,年齡就加一,當他的年齡增加到一定程度,就會被移動到老年代(年齡值默認為15)。對象晉升老年代的閾值可以通過-XX:MaxTenuringThreshold設置。
動態年齡判斷並進入老年代
為了更好的適應不同程序的內存狀況,虛擬機並不是永遠要求對象的年齡必須達到MaxTenuringThreshold才會晉升到老年代。如果在Survivor空間中相同年齡的所有對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就可以直接進入老年代,無需達到MaxTensuringThreshold的要求年齡。