內存分配與回收策略

整理自《深入理解 Java 虛擬機》。

對象的內存分配,大方向上講,就是在堆上分配,對象主要分配在新生代的 Eden 區上,如果啓動了本地線程分配緩衝,將按線程優先在 TLAB 上分配。少數情況下也可能會直接分配在老年代中,分配規則並不是百分百固定,其細節取決於當前使用的是哪一種垃圾收集器組合,還有虛擬機中與內存相關的參數的設置。以下是在使用 Serial+Serial Old 收集器下的內存分配和回收策略。

1. 對象優先在Eden分配

大多數情況下,對象在新生代 Eden 區中分配。當 Eden 區沒有足夠的空間進行分配時,虛擬機將發起一次 Minior GC。如果 GC 期間虛擬機發現已有的對象無法放入 Survivor 空間,那麼通過分配擔保機制提前轉移到老年代去。

2. 大對象直接進入老年代

需要大量連續內存空間的 Java 對象稱爲大對象,大對象的出現會導致還有不少內存空間時就提前觸發垃圾收集以獲取更大的連續的空間來進行大對象的分配。虛擬機提供了 -XX:PretenureSizeThreadshold 參數來設置大對象的閾值,超過閾值的對象直接分配到老年代。

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

虛擬機給每個對象定義了一個對象年齡(Age)計數器。如果對象在 Eden 出生並經過第一次Minor GC 後仍然存活,並且能被 Survivor 容納的話,將被移動到Survivor空間中,並且對象年齡設爲1,對象在 Survivor 區每次經過一次 Minor GC,年齡就加1,當它的年齡增加到一定程度(默認爲15歲),就將會被晉升到老年代中。對象晉升老年代的年齡閾值,可以通過參數-XX:MaxTenuringThreshold設置。

4. 動態對象年齡判定

對象的年齡到達了 MaxTenuringThreshold 可以進入老年代,同時,如果在 survivor 區中相同年齡所有對象大小的總和大於 Survivor 區的一半,年齡大於等於該年齡的對象就可以直接進入老年代。無須等到 MaxTenuringThreshold 中要求的年齡。

5. 空間分配擔保

如果經過一次 Minor GC 後有大量對象存活,而新生代的 Survivor 區很小,放不下這些大量存活的對象,所以需要老年代進行分配擔保,把 Survivor 區無法容納的對象直接進入老年代。 在發生 Minor GC之前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代所有對象總空間,如果這個條件成立,那麼 Minor GC 可以確保是安全的。JDK6 Update 24 之後的規則爲只要老年代的連續空間大於新生代對象總大小或者歷次晉升的平均大小就會進行 Minor GC,否則將進行 Full GC。

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