JVM記憶體:年輕代,老年代,永久代
Java 中的堆是 JVM 所管理的最大的一塊記憶體空間,主要用於存放各種類的例項物件,如下圖所示:
在 Java 中,堆被劃分成兩個不同的區域:新生代 ( Young )、老年代 ( Old)。新生代 ( Young ) 又被劃分為三個區域:Eden、S0、S1。 這樣劃分的目的是為了使 JVM 能夠更好的管理堆記憶體中的物件,包括記憶體的分配以及回收。
Java 中的堆也是 GC 收集垃圾的主要區域。GC 分為兩種:Minor GC、Full GC ( 或稱為 Major GC )。
1.年輕代
年輕代用來存放新近建立的物件,尺寸隨堆大小的增大和減小而相應的變化,預設值是保持為堆大小的1/15,可以通過 -Xmn 引數設定年輕代為固定大小,也可以通過 -XX:NewRatio 來設定年輕代與年老代的大小比例,年青代的特點是物件更新速度快,在短時間內產生大量的“死亡物件”。
年輕代的特點是產生大量的死亡物件,並且要是產生連續可用的空間, 所以使用複製清除演算法和並行收集器進行垃圾回收.對年輕代的垃圾回收稱作初級回收 (minor gc)。
初級回收將年輕代分為三個區域, 一個新生代 , 2個大小相同的復活代, 應用程式只能使用一個新生代和一個復活代, 當發生初級垃圾回收的時候,gc掛起程式, 然後將新生代和復活代中的存活物件複製到另外一個非活動的復活代中,然後一次性清除新生代和復活代,將原來的非復活代標記成為活動復活代。將在指定次數回收後仍然存在的物件移動到老年代中,初級回收後,得到一個空的可用的新生代。
新生代幾乎是所有 Java 物件出生的地方,即 Java 物件申請的記憶體以及存放都是在這個地方。Java 中的大部分物件通常不需長久存活,具有朝生夕滅的性質。 當一個物件被判定為 “死亡” 的時候,GC 就有責任來回收掉這部分物件的記憶體空間。新生代是 GC 收集垃圾的頻繁區域。 當物件在 Eden 出生後,在經過一次 Minor GC 後,如果物件還存活,並且能夠被另外一塊 Survivor 區域所容納,則使用複製演算法將這些仍然還存活的物件複製到另外一塊 Survivor 區域中,然後清理所使用過的 Eden 以及 Survivor 區域,並且將這些物件的年齡設定為1,以後物件在 Survivor 區每熬過一次 Minor GC,就將物件的年齡 + 1,當物件的年齡達到某個值時 ( 預設是 15 歲,可以通過引數 -XX:MaxTenuringThreshold 來設定 ),這些物件就會成為老年代。 但這也不是一定的,對於一些較大的物件 ( 即需要分配一塊較大的連續記憶體空間 ) 則是直接進入到老年代。
2.老年代
Full GC 是發生在老年代的垃圾收集動作,所採用的是標記-清除演算法。
現實的生活中,老年代的人通常會比新生代的人 “早死”。堆記憶體中的老年代(Old)不同於這個,老年代裡面的物件幾乎個個都是在 Survivor 區域中熬過來的,它們是不會那麼容易就 “死掉” 了的。因此,Full GC 發生的次數不會有 Minor GC 那麼頻繁,並且做一次 Full GC 要比進行一次 Minor GC 的時間更長。 另外,標記-清除演算法收集垃圾的時候會產生許多的記憶體碎片 ( 即不連續的記憶體空間 ),此後需要為較大的物件分配記憶體空間時,若無法找到足夠的連續的記憶體空間,就會提前觸發一次 GC 的收集動作。
3.永久代
永久代是Hotspot虛擬機器特有的概念,是方法區的一種實現,別的JVM都沒有這個東西。在Java 8中,永久代被徹底移除,取而代之的是另一塊與堆不相連的本地記憶體——元空間。
永久代或者“Perm Gen”包含了JVM需要的應用元資料,這些元資料描述了在應用裡使用的類和方法。注意,永久代不是Java堆記憶體的一部分。永久代存放JVM執行時使用的類。永久代同樣包含了Java SE庫的類和方法。永久代的物件在full GC時進行垃圾收集。