標籤:
幾條主要的最普遍的記憶體配置規則:
??
1.對象優先在Eden分配
?
大多數情況下,對象在新生代的Eden區中分配。
??
當Eden區沒有足夠的空間進行分配時,虛擬將發起一次Minor GC,如果GC後新生代中存活的對象無法全部放入Survivor空間,則需要通過分配擔保機制提前進入到老年代中,前提是老年代中不能容納所有存活對象,即只能容納部分。
??
則未能進入到老年代的存活對象將繼續分配在Eden區中
??
如果Eden區也還未能容納剩餘的存活對象虛擬機器拋出OutOfMemoryError錯誤
??
虛擬機器提供了-XX:+PrintGCDetails參數用於輸出收集器日誌參數。
??
Minor GC與Full GC的區別:
??
a.新生代GC(Minor GC):指發生在新生代的垃圾收集動作,因為Java對象大多都具備朝生夕死的特性,所以Minor GC非常頻繁,一般回收速度也比較快。
??
b.老年代GC(Major GC/Full GC):指發生在老年代的GC,出現了Major GC,經常會伴隨至少一次Minor GC(但非絕對,在ParallelScavenge收集器的收集策略裡就有直接進行Major GC的策略選擇過程)。
??
MajorGC的速度一般會比MinorGC慢10倍以上。
??
??
2.大對象直接進入老年代
?
所謂大對象是指,需要大量連續記憶體空間的Java對象
??
最典型的大對象就是那種很長的字串及數組。
??
大對象對虛擬機器的記憶體配置來說是一個壞訊息
??
經常出現大對象容易導致記憶體還有不少空間就提前觸發垃圾收集以擷取足夠的連續空間來"安置"它們。
?
??
虛擬機器擔任了一個-XX:PretenureSizeThreshold參數,令大於這個設定值的對象直接在老年代中分配。
??
這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的記憶體拷貝。
??
3.長期存活對象將進入老年代
?
虛擬機器採用了分代收集的思想來管理記憶體,那麼記憶體回收時就必須能夠識別哪些對象應當放在新生代,哪些對象應該放在老年代。
??
為了做到這點,虛擬機器給每個對象定義了一個對象年齡計數器。
??
如果對象在Eden區出生並經過第一次Minor GC後仍然存活,並且能被Survivor區容納的話,將被移到Survivor區中,並將對象年齡設定為1。
??
對象在Survivor區中每熬過一次Minor GC,年齡就增加1歲。
??
當它的年齡增加到一定程度(預設為15歲),就會被晉陞到老年代中。
??
對象晉陞老年代的年齡閾值,可以通過參數-XX:MaxTenuringThreshold來設定。
??
4.動態對象年齡判定
??
為了更好的適應不同程式的記憶體狀況,虛擬機器並不總是要求對象年齡必須達到MaxTenuringThreshold才能晉陞到老年氏
??
如果在Survivor空間中相同年齡所有對象大小的總和大於Survivor空間的一半,那麼年齡大於或等於該年齡的對象就直接進行老年代,無須等到MaxTenuringThreshold中要求的年齡。
??
5.空間分配擔保
?
在發生Minor GC時,虛擬機器會檢測之前每次晉陞到老年代的平均大小是否大於老年代剩餘空間的大小
??
如果大於,則改為直拉進行一次Full GC
??
如果小於,則查看HandlePromotionFailure設定是否允許擔保失敗;
??
如果允許,那隻會進行Minor GC;如果不允許,則要改為進行一次Full GC。
?
新生代使用複製收集演算法,但為了提高記憶體利用率,只使用其中一個Survivor空間來作為輪換備份
??
因此當出現大量對象在Minor GC後仍然存活的情況時,最需要老年代進行分配擔保,讓Survivor空間無法容納的對象直接進入老年代。
?
取平均值進行比較仍然是一種動態機率的手段,也就是說如果某次Minor GC存活的對象突增,遠高於平均值的話,依然會導致擔保失敗(HandlePromotionFailure)。如果出現了HandlePromotionFailure,那隻好在失敗後重新發起一次Full GC。雖然擔保失敗時繞圈子是最大的,但是大部情況下還是會將HandlePromotionFailure開關開啟,避免Full GC過於頻繁。
《深入理解Java虛擬機器》筆記 第三章 記憶體配置與回收策略