對象的內存分配往大的方向講,是在堆上分配(但也有可能是在棧上分配),對象主要分配在Eden區上,如果啟動了本地線程緩沖,按線程優先在TLAB上分配。也有少數情況會直接分配在老年代中。分配規則不是百分百固定,分配細節由虛擬機與虛擬機中與內存相關的參數設定。
以下是常見的幾條內存分配規則
對象優先在Eden區分配
大多數情況下,對象在新生代的Eden區分配,當Eden區沒有足夠的內存進行分配時,虛擬機將發起一次MinorGC,將Eden區的存活對象與Survivor(From)中的存活對象通過復制算法轉移到另一個Survivor區(To),如果Survivor區(To)裝不下,則轉移到擔保區(老年代),再在Eden去給新對象分配內存。如果如果Survivor區(To)裝的下,Eden區的存活對象與Survivor(From)中的存活對象就會轉移到另一個Survivor區(To),再試著在Eden區分配新的空間給新對象。
Minor GC:發生在新生代的垃圾收集動作,新生代具有朝生夕滅的特性,所以Minor GC非常頻繁,回收速度也比較快。
Full GC/Major GC:發生在老年代的GC,Full GC速度一般在比Minor GC慢10倍以上
大對象直接進入老年代
大對象就是需要連續內存分配空間的Java對象,典型的有很長的字符串和數組如byte[] mybyte=new byte[2*1024*1024]; 虛擬機提供了-XX:PretenureSizeThreshold參數,令大于這個的值直接在老年代分配,避免在Eden區及兩個Survivor區之間進行大量的復制
長期存活的對象將進入老年代
虛擬機給每個對象定義一個年齡計數器,對象創建之后,每進行一次Minor GC之后還存活,并且保存在了Survivor區,年齡就加1,當年齡到達了一定的程度,就晉升到老年區。可通過參數-XX:MaxTenuringThreshold=2設置。(默認15)
動態對象年齡判定
虛擬機并不是永遠年齡達到MaxTenuringThreshold的值才晉升,當相同年齡所有的對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象可以直接進入老年代
空間分配擔保
在發生Minor GC之前,虛擬機會首先檢查老年代最大可用的連續空間是否大于新生代所有對象的大小,如果大于,那么這次Minor GC是安全的,如果小于,那么虛擬機會繼續查看HandlePromotionFailure設置的值是否允許擔保失敗,如果允許,則繼續檢查老年代最大可用的連續空間是否大于歷次晉升到老年代對象的平均大小,如果大于,將嘗試進行一次Minor GC,盡管這次Minor GC是有風險的,如果小于或者HandlePromotionFailure設置為不允許,那么要改為進行一次FullGC
"風險"是指如果這次的存活對象很多,且Survivor無法容納下,需要將無法容納的對象直接進入老年代,如果進入老年的對象的大小遠大于之前每一次回收晉升到老年代對象的平均大小,老年代的剩余空間無法容納下這些對象,就需要進行一次Full GC讓老年代騰出更多的空間。