JVM年輕代,老年代,永久代詳解

前言

最近被問到了這個問題,解釋的不是很清晰,有一些概念略微模糊,在此進行整理和記錄,分享給大家。本篇文章主要講解內存區域的年輕代,老年代和永久代,略微提及一些垃圾回收算法,下面是正文。

堆整體

堆主要用於存放各種類的實例對象和數組。在java中被分為兩個區域:年輕代和老年代。在java中還有一個永久代的意思,這裡最後會單獨說明。

年輕代和老年代的劃分是為了更好的內存分派及回收。提高效率。
堆是垃圾回收機制的重點區域。我們知道垃圾回收機制有三種,minor gc,major gc 和full gc。針對於堆的就是前兩種。年輕代的叫 minor gc,老年代的叫major gc。

年輕代

年輕代用來存放新近創建的對象,尺寸隨堆大小的增加和減少而相應的變化,默認值是保持為堆的1/15。
年輕代的大小可以通過-xmn設置固定大小,也可以通過-xx:newratio設置年輕代和年老代的比例。
年輕代中存在的對象是死亡非常快的。存在朝生夕死的情況。
所以為了提高年輕代的垃圾回收效率,又將年輕代劃分為三個區域,一個eden和兩個sunrvivor from。

eden和survivor默認比例是8:1:1,進行垃圾回收採用的是分代複製算法。每次新生代的使用,會是eden區和一塊survivor區。當我們進行垃圾回收的時候,清除正在使用的區域,將其中的存貨對象,放入到另一個survivor區域,並進行整理,保證空間的連續。如果對象長時間存活,則將對象移動到老年區。存活下來的對象,他的年齡會增長1。當對象的年齡一次次存活,一次次增長,到達15的時候,這些對象就會移步到老年代。在年輕代執行gc的時候,如果老年代的連續空間小於新生代對象的總大小,就會觸發一次full gc。是為了給新生代做擔保,保證新生代的老年對象可以順利的進入到老年代的內存區。

老年代

老年代中存放的對象是存活了很久的,年齡大於15的對象。在老年代觸發的gc叫major gc也叫full gc。full gc會包含年輕代的gc。但老年代只要執行gc就一定是full gc。
full gc採用的是標記-清除算法。會產生內存碎片。在執行full gc的情況下,會阻塞程序的正常運行。老年代的gc比年輕代的gc效率上慢10倍以上。對效率有很大的影響。

永久代

永久代是hotspot虛擬機,也就是我們使用的java虛擬機的特有的概念,他不屬於堆內存,是方法區的一種實現,各大廠商對方法區有各自的實現。永久代存放jvm運行時,需要的類,包含java庫的類和方法,在觸發full gc的情況下,永久代也會被進行垃圾回收。永久代的內存溢出也就是 pergen space。

元空間

元空間是metaspace,在jdk1.8的時候,jvm移除了永久代的概念,元空間也是對java虛擬機的方法區的一種實現。元空間與永久代最大的區別在於,元空間不在虛擬機中,使用本地內存。通過配置如下參數可以更改元空間的大小。
-XX:MetaspaceSize:初始空間的大小。達到該值就會觸發垃圾收集進行類型卸載,同時GC會對該值進行調整:如果釋放了大量的空間,就適當降低該值;如果釋放了很少的空間,那麼在不超過MaxMetaspaceSize時,適當提高該值。
-XX:MaxMetaspaceSize,最大空間,默認是沒有限制的。
永久代的回收會隨着full gc進行移動,消耗性能。每種類型的垃圾回收都需要特殊處理元數據。將元數據剝離出來,簡化了垃圾收集,提高了效率。