以下為對象在內(nèi)存中分配的規(guī)則,這些規(guī)則并不是百分之百固定的,其細(xì)節(jié)取決于正在使用的垃圾收集策略,當(dāng)然還有與虛擬機的內(nèi)存相關(guān)參數(shù)設(shè)置有關(guān)道盏。
1. 對象優(yōu)先在Eden分配
一般,對象在新生代Eden區(qū)中分配文捶,當(dāng)Eden區(qū)沒有足夠空間進(jìn)行分配時(一般不會將新生對象直接放入Survivor中荷逞,它只保存上一次GC還存活的對象),虛擬機將發(fā)生一次Minor GC(當(dāng)Eden空間不足粹排,就會發(fā)生對新生代的GC)种远。
2. 大對象直接進(jìn)入老年代
所謂的大對象是指,需要大量連續(xù)內(nèi)存空間的Java對象顽耳,最經(jīng)典的大對象就是那種很長的字符串以及數(shù)組坠敷。經(jīng)常出現(xiàn)大對象容易導(dǎo)致內(nèi)存還有不少空間時就提前出發(fā)垃圾收集。所以應(yīng)當(dāng)盡量避免短命大對象的使用射富。
3. 長期存活的對象將進(jìn)入老年代
對象的年齡:虛擬機給每個對象定義了一個對象年齡計數(shù)器膝迎,如果對象在Eden出生并經(jīng)過第一次的MinorGC后仍然存活,并且能被Survivor區(qū)中每“熬過”一次Minor GC胰耗,年齡就增加一歲限次,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲),就會被晉升到老年代中柴灯。
4. 動態(tài)對象年齡判定
為了更好的適應(yīng)不同程度的內(nèi)存狀況卖漫,虛擬機并不是永遠(yuǎn)地要求對象的年齡必須達(dá)到閥值才能晉升老年代费尽,如果Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進(jìn)入老年代懊亡,無須等到閥值中要求的年齡依啰。
5. 空間分配擔(dān)保
- 在發(fā)生MinorGC之前乎串,虛擬機會先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象的總空間店枣,如果這個條件成立,那么Minor GC 可以確保是安全的叹誉。
- 如果不成立鸯两,則虛擬機會查看HandlePromotionFailure設(shè)置值是否允許擔(dān)保失敗。如果允許长豁,那么會繼續(xù)查找老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小钧唐,如果大于,將嘗試著進(jìn)行一次Minor GC匠襟,盡管這次MinorGC是有風(fēng)險的
- 如果小于钝侠,或者HandlePromotionFailure設(shè)置不允許冒險,那這時也要改為進(jìn)行一次Full GC酸舍。
觸發(fā)Full GC的五種情況
- 直接調(diào)用System.gc()
- 老年代空間不足
- 永久代空間滿
Java 8 中已經(jīng)移除了永久代帅韧,改用元空間。元空間的本質(zhì)和永久代類似啃勉,都是對JVM規(guī)范中方法區(qū)的實現(xiàn)忽舟。不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機中,而是使用本地內(nèi)存淮阐。因此叮阅,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制泣特。
Minor GC 會清理新生代(滿或者無法分配大對象)浩姥,Major GC是清理永久代。Full GC是清理整個堆空間——包括新生代和老年代状您。
- 在使用CMS策略對老年代進(jìn)行垃圾回收時
- promotion failed: 進(jìn)行Minor GC時及刻,Survivor 放不下上一次存活的對象,對象只能放入老年代竞阐,而此時老年代也放不下造成的缴饭。
- concurrent mode failure:在執(zhí)行CMS GC的過程中同時有對象要放入老年代,而此時老年代空間不足造成的骆莹。
- 統(tǒng)計得到的Minor GC 晉升到老年代的平均大小大于老年代的剩余空間
HotSpot 為了避免由于新生代對象晉升到老年代導(dǎo)致老年代空間不足的現(xiàn)象颗搂,在進(jìn)行Minor GC時,做了有一個判斷幕垦,如果之前統(tǒng)計所得的MInor GC 晉升到老年代的平均大小大于老年代的剩余空間丢氢,那么就直接觸發(fā) Full GC傅联。