Java虛擬機內存分配與回收策略

內存分配與回收策略

Minor GC 和 Full GC

  • Minor GC:發生在新生代上,由於新生代對象存活時間很短,所以 Minor GC 會頻繁執行, 執行的速度通常也會比較快。java

  • Full GC:又稱Major GC,發生在老年代上,老年代對象其存活時間長, 所以 Full GC 不多執行,執行速度會比 Minor GC 慢不少。算法

內存分配策略

  • 堆內存:

 

  • 分配策略:

 

1. 對象優先在 Eden 分配

大多數狀況下,對象在新生代 Eden 區分配,當 Eden 區空間不夠時,發起 Minor GC。數組

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

大對象是指須要連續內存空間的對象,最典型的大對象是那種很長的字符串以及數組。安全

常常出現大對象會提早觸發垃圾收集以獲取足夠的連續空間分配給大對象。spa

-XX:PretenureSizeThreshold,大於此值的對象直接在老年代分配,避免在 Eden 區和 Survivor 區之間的大量內存複製。3d

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

爲對象定義年齡計數器,對象在 Eden 出生並通過 Minor GC 依然存活, 將移動到 Survivor 中,年齡就增長 1 歲,增長到必定年齡則移動到老年代中。對象

-XX:MaxTenuringThreshold 用來定義年齡的閾值。token

4. 動態對象年齡斷定

虛擬機並非永遠地要求對象的年齡必須達到 MaxTenuringThreshold 才能晉升老年代, 若是在 Survivor 中相同年齡全部對象大小的總和大於 Survivor 空間的一半, 則年齡大於或等於該年齡的對象能夠直接進入老年代,無需等到 MaxTenuringThreshold 中要求的年齡。內存

5. 空間分配擔保

在發生 Minor GC 以前,虛擬機先檢查老年代最大可用的連續空間是否大於新生代全部對象總空間,若是條件成立的話,那麼 Minor GC 能夠確認是安全的。字符串

若是不成立的話虛擬機會查看 HandlePromotionFailure 設置值是否容許擔保失敗,若是容許那麼就會繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代對象的平均大小,若是大於,將嘗試着進行一次 Minor GC;若是小於,或者 HandlePromotionFailure 設置不容許冒險,那麼就要進行一次 Full GC。

Full GC 的觸發條件

對於 Minor GC,其觸發條件很是簡單,當 Eden 空間滿時,就將觸發一次 Minor GC。 而 Full GC 則相對複雜,有如下條件:

1. 調用 System.gc()

只是建議虛擬機執行 Full GC,可是虛擬機不必定真正去執行。不建議使用這種方式,而是讓虛擬機管理內存。

2. 老年代空間不足

老年代空間不足的常見場景爲前文所講的大對象直接進入老年代、長期存活的對象進入老年代等。

爲了不以上緣由引發的 Full GC,應當儘可能不要建立過大的對象以及數組。 除此以外,能夠經過 -Xmn 虛擬機參數調大新生代的大小,讓對象儘可能在新生代被回收掉,不進入老年代。 還能夠經過 -XX:MaxTenuringThreshold 調大對象進入老年代的年齡,讓對象在新生代多存活一段時間。

3. 空間分配擔保失敗

使用複製算法的 Minor GC 須要老年代的內存空間做擔保,若是擔保失敗會執行一次 Full GC。 具體內容請參考上面的第五小節。

4. JDK 1.7 及之前的永久代空間不足

在 JDK 1.7 及之前,HotSpot 虛擬機中的方法區是用永久代實現的, 永久代中存放的爲一些 Class 的信息、常量、靜態變量等數據。

當系統中要加載的類、反射的類和調用的方法較多時,永久代可能會被佔滿, 在未配置爲採用 CMS GC 的狀況下也會執行 Full GC。 若是通過 Full GC 仍然回收不了,那麼虛擬機會拋出 java.lang.OutOfMemoryError。

爲避免以上緣由引發的 Full GC,可採用的方法爲增大永久代空間或轉爲使用 CMS GC。

5. Concurrent Mode Failure

執行 CMS GC 的過程當中同時有對象要放入老年代,而此時老年代空間不足 (多是 GC 過程當中浮動垃圾過多致使暫時性的空間不足), 便會報 Concurrent Mode Failure 錯誤,並觸發 Full GC。

相關文章
相關標籤/搜索