《JVM第7課》堆區

凡人编程传(Java)發表於2024-11-06

1.概念

堆是JVM中最重要的一塊區域,JVM規範中規定所有的物件和陣列都應該存放在堆中,在執行位元組碼指令時,會把建立的物件存入堆中,物件的引用地址存入虛擬機器棧的棧幀中。不過當方法執行完之後,剛剛所建立的物件並不會立馬被回收,也就是說物件並不會隨著棧幀的消失而消失,而是要等JVM後臺執行GC後,物件才會被回收。

2.指定堆大小

-Xms:指定堆的初始記憶體大小,ms(memory start)。等價於 -XX:InitialHeapSize;

-Xmx:指定堆的最大記憶體大小,mx(memory max)。等價於 -XX:MaxHeapSize;

一般會把 -Xms 和 -Xmx 設定為一樣,這樣JVM就不需要在GC後去修改堆的記憶體大小了,提高了效率。預設情況下,-Xms等於實體記憶體大小/64,-Xmx等於實體記憶體大小/4。

3.新生代和老年代

垃圾回收演算法有很多,但基本上都會把記憶體分為新生代和老年代兩塊區域。新生代存放新建立的物件,老年代存放執行了許多次GC(預設為15次)後還存活的物件。

可以透過 -XX:NewRatio 引數來配置老年代和新生代的比例,預設為 -XX:NewRatio=2,表示新生代佔1,老年代佔2。一般是不需要調整的,只有明確知道存活時間比較長的物件偏多或偏少,才需要調整 -XX:NewRatio 的比值。

3.1 新生代

新生代又可以分為 Eden(伊甸園區)和 S0、S1 區。

Eden: 伊甸園區,新物件都會先放到Eden區。

S0、S1區: Survivor0、Survivor1區,也可以叫做from、to區,用來存放MinorGC(YGC)後存在的物件。

預設情況下 Eden、S0、S1 的比例為 8:1:1,也就是說Eden區佔新生代大小的 8/10。可以透過 -XX:SurvivorRatio 來調整。

3.2 老年代

老年代存放執行了許多次GC後還存活的物件。老年代預設佔記憶體區域的2/3。

3.3 動畫演示

動畫演示物件在記憶體各區域中的流轉過程

  1. 物件會先被放到Eden區。
  2. 執行 Young GC 後會被放到S0或S1區,S0和S1不能同時非空,物件會在S0和S1之間反覆跳躍。
  3. 在執行一定次數(預設為15次)的 Young GC 後假設物件還沒有被回收掉,就會進入老年代區域。
  4. 如果新物件大小超過了 Eden 區剩餘空間大小,則會直接進入S0或S1,如果S0或S1放不下則會直接進入老年代。
  5. 老年代繼續執行 Old GC 對其中物件進行回收。
  6. 這裡的 Young GC 和 Old GC 也可叫做 Minor GC 和 Major GC,它們並不是垃圾回收器的名字,只是代表年輕代和老年代的垃圾回過程

4.分代收集理念

上面的新生代老年代就是分代收集理念,有些時候會被叫做分代收集演算法,但其實它是一種理念。預設幾乎所有的垃圾回收演算法都是採用分代收集理念。

為什麼垃圾回收演算法要把記憶體區域分為新生代和老年代,新生代裡又包含Eden區、Survivor0、Survivor1區呢?

這是因為不同的物件存活時長是不一樣的,所以要針對存活時長不同的物件採取不同的垃圾回收演算法。

  • 新生代中的物件存活時間比較短,那麼就可以採取“複製演算法”(後面的章節會介紹)。
  • 老年代中的物件存活時間比較長,所以不太適合用複製演算法,可以用“標記-清除演算法”或“標記-整理演算法”(後面的章節會介紹)。

相關文章