前言
對象的內(nèi)存分配,往大方向講,就是在堆上分配(但也可能經(jīng)過JIT編譯后被拆散為標量類型并間接地棧上分配)盲厌,對象主要分配在新生代的Eden區(qū)上馒过,如果啟動了本地線程分配緩沖臭脓,將按線程優(yōu)先在TLAB上分配。少數(shù)情況下也可能會直接分配在老年代中腹忽,分配的規(guī)則并不是百分之百固定的来累,其細節(jié)取決于當前使用的是哪一種垃圾收集器組合,還有虛擬機中與內(nèi)存相關(guān)的參數(shù)的設(shè)置窘奏。
對象優(yōu)先在Eden分配
大多數(shù)情況下嘹锁,對象在新生代Eden區(qū)中分配。分配對象時着裹,假如Eden區(qū)沒有足夠空間容納該對象時领猾,虛擬機將發(fā)起一次Minor GC,經(jīng)過這次GC骇扇,Eden區(qū)中仍然存活的對象將被轉(zhuǎn)移到Survivor區(qū)摔竿,并且年齡對象設(shè)置為1,如果Survivor區(qū)也無法容納從Eden區(qū)轉(zhuǎn)移過來的對象少孝,就會通過分配擔保機制提前轉(zhuǎn)移到老年代去继低。對象在Survivor區(qū)中每“熬過”一次Minor GC,年齡就增加1歲稍走,當它的年齡增加到一定程度(默認為15歲)袁翁,就將會被晉升到老年代中冷溃。對象晉升老年代的年齡閾值,可以通過參數(shù)-XX:MaxTenuringThreshold設(shè)置梦裂。
大對象直接進入老年代
虛擬機提供了一個-XX:PretenureSizeThreshold參數(shù)似枕,令大于這個設(shè)置值的對象直接在老年代分配。由于新生代采用復(fù)制算法收集內(nèi)存年柠,這樣做的目的是避免在Eden區(qū)及兩個Survivor區(qū)之間發(fā)生大量的內(nèi)存復(fù)制凿歼。
注意 PretenureSizeThreshold參數(shù)只對Serial和ParNew兩款收集器有效,Parallel Scavenge收集器不認識這個參數(shù)冗恨,Parallel Scavenge收集器一般并不需要設(shè)置答憔。如果遇到必須使用此參數(shù)的場合,可以考慮ParNew加CMS的收集器組合掀抹。
長期存活的對象將進入老年代
虛擬機給每個對象定義了一個對象年齡(Age)計數(shù)器虐拓。如果對象在Eden出生并經(jīng)過第一次Minor GC后仍然存活,并且能被Survivor容納的話傲武,將被移動到Survivor空間中蓉驹,并且對象年齡設(shè)為1。對象在Survivor區(qū)中每“熬過”一次Minor GC揪利,年齡就增加1歲态兴,當它的年齡增加到一定程度(默認為15歲),就將會被晉升到老年代中疟位。對象晉升老年代的年齡閾值瞻润,可以通過參數(shù)-XX:MaxTenuringThreshold設(shè)置
動態(tài)對象年齡判定
為了能更好地適應(yīng)不同程序的內(nèi)存狀況,虛擬機并不是永遠地要求對象的年齡必須達到了MaxTenuringThreshold才能晉升老年代甜刻,如果在Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半绍撞,年齡大于或等于該年齡的對象就可以直接進入老年代,無須等到MaxTenuringThreshold中要求的年齡得院。
空間分配擔保
在發(fā)生Minor GC之前傻铣,虛擬機會先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象總空間,如果這個條件成立尿招,那么Minor GC可以確保是安全的矾柜。如果不成立,則虛擬機會查看HandlePromotionFailure設(shè)置值是否允許擔保失敗就谜。如果允許怪蔑,那么會繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小,如果大于丧荐,將嘗試著進行一次Minor GC缆瓣,盡管這次Minor GC是有風(fēng)險的;如果小于虹统,或者HandlePromotionFailure設(shè)置不允許冒險弓坞,那這時也要改為進行一次Full GC隧甚。
JDK 6 Update 24之后的規(guī)則變?yōu)橹灰夏甏倪B續(xù)空間大于新生代對象總大小或者歷次晉升的平均大小就會進行Minor GC,否則將進行Full GC渡冻。
Minor GC和Full GC
新生代GC(Minor GC):指發(fā)生在新生代的垃圾收集動作戚扳,因為Java對象大多都具備朝生夕滅的特性,所以Minor GC非常頻繁族吻,一般回收速度也比較快帽借。
老年代GC(Major GC/Full GC):指發(fā)生在老年代的GC,出現(xiàn)了Major GC超歌,經(jīng)常會伴隨至少一次的Minor GC(但非絕對的砍艾,在Parallel Scavenge收集器的收集策略里就有直接進行Major GC的策略選擇過程)。Major GC的速度一般會比Minor GC慢10倍以上巍举。
參考整理自:《深入理解Java虛擬機:JVM高級特性與最佳實踐》 — 周志明