內存分配與回收策略

Java 內存管理自動化的解決了兩個問題:
1) 給對象分配內存;

2) 回收內存

新建對象主要分配在新生代的 Eden 區域,如果啓動了本地線程分配緩衝,將按線程優先在 TLAB 上分配。少數情況也可能會直接分配在老年代中。分配的規則取決於當前使用的垃圾收集器組合,及其他與內存相關的設置參數。

以下是幾條普遍的內存分配規則:

1.1 對象優先在 Eden 區分配

大多數情況下,對象在新生代 Eden 區分配,當該區域沒有足夠的空間時,虛擬機將會發起 Minor GC 進行垃圾收集。

1.2 大對象直接分配至老年代

這裏的大對象是指需要大量連續內存空間的 Java 對象,如很長的字符串、數組等。

通過設置 -XX:PretenureSizeThread 參數,可將大於該值的對象直接在老年代分配內存。這樣可以避免在 Eden 區及兩個 Survivor 區之間發生大量的內存複製(基於複製算法的內存收集)。

參數設置格式如下:
-XX:PretenureSizeThread=3145728 // 3M,該參數不能直接設置爲3M

1.3 長期存活的對象將進入老年代

Java 虛擬機給每個對象定義了一個對象年齡(Age)計數器,若對象在 Eden 區經過一次 Minor GC後仍然存活,並且被移到 Survivor 區,則該對象年齡置爲1,此後,該對象在 Survivor 區每經過一次 Minor GC,年齡就加1,當增加到一定值時(年齡閾值,默認15 age,可通過 -XX:MaxTenuringThreshold 設置),則會被晉升到老年代中。

1.4 動態對象年齡判斷

當然,虛擬機並不是永遠要求對象的年齡必須達到閾值才能進入老年代區,若在 Survivor 空間中相同年齡所有對象所佔空間大於 Survivor 空間的一半,年齡大於或等於該年齡的對象就可以直接先進入老年代區,無須等到 MaxTenuringThreshold 設置的閾值

1.5 空間分配擔保

在發生 Minor GC 之前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代所有對象總空間,大於的話,則說明 Minor GC 確保是安全的。

否則虛擬機會查看 HandlePromotionFailure 設置值是否允許擔保失敗。
若允許,虛擬機會檢查老年代最大可用的連續空間是否大於歷次晉升到老年代對象的平均大小,若大於,則嘗試進行一次 Minor GC;若小於,或者 HandlePromotionFailure 設置不允許冒險,那這時也要改爲進行一次 Full GC。



參考資料:
深入理解Java虛擬機:JVM高級特性與最佳實踐

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章