JVM內存分配機制與回收策略選擇-JVM學習筆記(2)

Java體系中的自動內存管理主要包括了2個方面:java

  1. 自動地給對象分配內存。
  2. 自動地回收分配給對象地內存。

本文也圍繞這兩個點展開 算法

一. 內存分配規則

1.優先在Eden區分配

大多數狀況下,JVM會在 Eden 區優先分配對象,若是 Eden 沒有足夠的空間,則進行一次 Minor GC 。經過參數 -XX:+PrintGCDetails 可讓虛擬機在進行垃圾回收時打印日誌,方便咱們看到回收先後的內存佔用狀況。優化

例: 假如如今內存大小指定以下:spa

  • 新生代 ->10M
    • Eden區 -> 8M
    • from區 -> 1M
    • to 區 -> 1M
  • 老年代 -> 10M

而後咱們又前後在代碼中建立4個對象:3d

byte[] byte1 = new byte[2MB];
byte[] byte2 = new byte[2MB];
byte[] byte3 = new byte[2MB];
byte[] byte4 = new byte[4MB];
複製代碼

當建立完第三個對象後,Eden區已經用掉了6M的空間來存放 byte1,byte2,byte3 三個對象,再建立第四個對象時,Eden區加上一個from區已經放不下了,如先前所述,此時會觸發一次 MinorGC ,將三個2MB的對象轉移到老年代中,騰出Eden區的空間給 第四個對象。日誌

因此,執行後的內存狀況以下:code

  • 新生代 -> 10M
    • Eden 區 -> 8M (剩餘4M) 存放 byte4
    • from區  -> 1M
    • to區      -> 1M
  • 老年代 -> 10M (剩餘4M) 存放byte1,byte2,byte3。

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

經過 -XX:PretentureSizeThreshold 參數設置大於這個值的對象直接分配到老年代。cdn

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

怎麼算是長期存活 ?對象

JVM給每一個對象定義了一個 對象年齡計數器 。當對象一開始被分配到新生代Eden區,通過一次  MniorGC 
後仍然存活,而且Survivor區可以容納它,則此對象被轉移到 Survivor 區,年齡變爲1。
Survivor 區中的對象沒熬過一次 MniorGC ,年齡就漲1,當年齡達到咱們設定的年齡閾值(JVM默認設定15)時,就會進入老年代。15歲就已經步入老年....
年齡閾值可經過參數 -XX:MaxTenuringThreshold = 指定值 來設定。
blog

對對象年齡斷定的優化

JVM中,若是Survivor區中的相同年齡全部對象的大小總和大於Survivor空間的一半,那麼這些同學們就直接進入老年代。無須等到上面的年齡閾值。

二. 空間分配擔保機制與回收策略(Mnior GC仍是Full GC)

首先介紹一下 Mnior GC  和 Full GC  的區別:

MniorGC :  發生在新生代的垃圾回收活動,因爲新生代的Java對象 短命的特性,這種垃圾回收活動頻繁,回收速度較快。(就像掃碎紙屑) Full GC : 發生在老年的垃圾回收活動,不過出現一次  Full GC,也會伴隨着一次 MniorGC,因爲老年代中的對象基本都是大對象,長命,因此Full GC的速度比Mnior GC 的速度慢10倍以上。(就像搬大石頭)

新生代的垃圾回收算法採用的是 複製算法 ,當進行一次 Mnior GC 時,會將新生代的活動區域( Eden區 和Survivor中的 From區 )中的存活對象複製到 Survivor中的 to區 ,若是 to 區的內存不足以放下這些對象,那麼這時就須要老年代出馬,進行分配擔保機制,將放不下的對象放到老年代。
    因此,在進行 Monior GC  前,JVM會作如下流程的檢查,以確認老年代是否可以放得下那些對象,來選擇進行 Mnior GC  仍是  Full GC 。

image.png

Reference:
深刻理解Java虛擬機

image.png
相關文章
相關標籤/搜索