對象的內(nèi)存分配往大的方向講疫萤,是在堆上分配(但也有可能是在棧上分配)偷溺,對象主要分配在Eden區(qū)上拐迁,如果啟動了本地線程緩沖官地,按線程優(yōu)先在TLAB上分配怒详。也有少數(shù)情況會直接分配在老年代中炉媒。分配規(guī)則不是百分百固定,分配細節(jié)由虛擬機與虛擬機中與內(nèi)存相關(guān)的參數(shù)設(shè)定昆烁。
以下是常見的幾條內(nèi)存分配規(guī)則
對象優(yōu)先在Eden區(qū)分配
大多數(shù)情況下吊骤,對象在新生代的Eden區(qū)分配,當(dāng)Eden區(qū)沒有足夠的內(nèi)存進行分配時静尼,虛擬機將發(fā)起一次MinorGC白粉,將Eden區(qū)的存活對象與Survivor(From)中的存活對象通過復(fù)制算法轉(zhuǎn)移到另一個Survivor區(qū)(To)传泊,如果Survivor區(qū)(To)裝不下,則轉(zhuǎn)移到擔(dān)保區(qū)(老年代)鸭巴,再在Eden去給新對象分配內(nèi)存眷细。如果如果Survivor區(qū)(To)裝的下,Eden區(qū)的存活對象與Survivor(From)中的存活對象就會轉(zhuǎn)移到另一個Survivor區(qū)(To)鹃祖,再試著在Eden區(qū)分配新的空間給新對象溪椎。
Minor GC:發(fā)生在新生代的垃圾收集動作,新生代具有朝生夕滅的特性恬口,所以Minor GC非常頻繁池磁,回收速度也比較快。
Full GC/Major GC:發(fā)生在老年代的GC楷兽,F(xiàn)ull GC速度一般在比Minor GC慢10倍以上
大對象直接進入老年代
大對象就是需要連續(xù)內(nèi)存分配空間的Java對象地熄,典型的有很長的字符串和數(shù)組如byte[] mybyte=new byte[2*1024*1024]; 虛擬機提供了-XX:PretenureSizeThreshold參數(shù),令大于這個的值直接在老年代分配芯杀,避免在Eden區(qū)及兩個Survivor區(qū)之間進行大量的復(fù)制
長期存活的對象將進入老年代
虛擬機給每個對象定義一個年齡計數(shù)器端考,對象創(chuàng)建之后,每進行一次Minor GC之后還存活揭厚,并且保存在了Survivor區(qū)却特,年齡就加1,當(dāng)年齡到達了一定的程度筛圆,就晉升到老年區(qū)裂明。可通過參數(shù)-XX:MaxTenuringThreshold=2設(shè)置太援。(默認15)
動態(tài)對象年齡判定
虛擬機并不是永遠年齡達到MaxTenuringThreshold的值才晉升闽晦,當(dāng)相同年齡所有的對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象可以直接進入老年代
空間分配擔(dān)保
在發(fā)生Minor GC之前提岔,虛擬機會首先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象的大小仙蛉,如果大于,那么這次Minor GC是安全的碱蒙,如果小于荠瘪,那么虛擬機會繼續(xù)查看HandlePromotionFailure設(shè)置的值是否允許擔(dān)保失敗,如果允許赛惩,則繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小哀墓,如果大于,將嘗試進行一次Minor GC,盡管這次Minor GC是有風(fēng)險的喷兼,如果小于或者HandlePromotionFailure設(shè)置為不允許篮绰,那么要改為進行一次FullGC
"風(fēng)險"是指如果這次的存活對象很多,且Survivor無法容納下褒搔,需要將無法容納的對象直接進入老年代阶牍,如果進入老年的對象的大小遠大于之前每一次回收晉升到老年代對象的平均大小喷面,老年代的剩余空間無法容納下這些對象,就需要進行一次Full GC讓老年代騰出更多的空間走孽。