1. 程式人生 > >JVM內存:年輕代、老年代、永久代(推薦 轉)

JVM內存:年輕代、老年代、永久代(推薦 轉)

回收 以及 平靜的 保持 size 個人 對象更新 you 應用

參考文章:


1.Java 新生代、老年代、持久代、元空間
2.Java內存與垃圾回收調優
3.方法區的Class信息,又稱為永久代,是否屬於Java堆?

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時進行垃圾收集。

Jvm區域總體分兩類,heap區和非heap區。heap區又分:Eden Space(伊甸園)、Survivor Space(幸存者區)、Tenured Gen(老年代-養老區)。 非heap區又分:Code Cache(代碼緩存區)、Perm Gen(永久代)、Jvm Stack(java虛擬機棧)、Local Method Statck(本地方法棧)。

HotSpot虛擬機GC算法采用分代收集算法:

1、一個人(對象)出來(new 出來)後會在Eden Space(伊甸園)無憂無慮的生活,直到GC到來打破了他們平靜的生活。GC會逐一問清楚每個對象的情況,有沒有錢(此對象的引用)啊,因為GC想賺錢呀,有錢的才可以敲詐嘛。然後富人就會進入Survivor Space(幸存者區),窮人的就直接kill掉。

2、並不是進入Survivor Space(幸存者區)後就保證人身是安全的,但至少可以活段時間。GC會定期(可以自定義)會對這些人進行敲詐,億萬富翁每次都給錢,GC很滿意,就讓其進入了Genured Gen(養老區)。萬元戶經不住幾次敲詐就沒錢了,GC看沒有啥價值啦,就直接kill掉了。

3、進入到養老區的人基本就可以保證人身安全啦,但是億萬富豪有的也會揮霍成窮光蛋,只要錢沒了,GC還是kill掉。

分區的目的:新生區由於對象產生的比較多並且大都是朝生夕滅的,所以直接采用標記-清理算法。而養老區生命力很強,則采用復制算法,針對不同情況使用不同算法。

非heap區域中Perm Gen中放著類、方法的定義,jvm Stack區域放著方法參數、局域變量等的引用,方法執行順序按照棧的先入後出方式。

GC工作機制

SUN的jvm內存池被劃分為以下幾個部分:

Eden Space (heap)

內存最初從這個線程池分配給大部分對象。

Survivor Space (heap)

用於保存在eden space內存池中經過垃圾回收後沒有被回收的對象。

Tenured Generation (heap)

用於保持已經在survivor space內存池中存在了一段時間的對象。

Permanent Generation (non-heap)

保存虛擬機自己的靜態(reflective)數據,例如類(class)和方法(method)對象。Java虛擬機共享這些類數據。這個區域被分割為只讀的和只寫的。

Code Cache (non-heap)

HotSpot Java虛擬機包括一個用於編譯和保存本地代碼(native code)的內存,叫做“代碼緩存區”(code cache)。

簡單來講,jvm的內存回收過程是這樣的:

對象在Eden Space創建,當Eden Space滿了的時候,gc就把所有在Eden Space中的對象掃描一次,把所有有效的對象復制到第一個Survivor Space,同時把無效的對象所占用的空間釋放。當Eden Space再次變滿了的時候,就啟動移動程序把Eden Space中有效的對象復制到第二個Survivor Space,同時,也將第一個Survivor Space中的有效對象復制到第二個Survivor Space。如果填充到第二個Survivor Space中的有效對象被第一個Survivor Space或Eden Space中的對象引用,那麽這些對象就是長期存在的,此時這些對象將被復制到Permanent Generation。

若垃圾收集器依據這種小幅度的調整收集不能騰出足夠的空間,就會運行Full GC,此時jvm gc停止所有在堆中運行的線程並執行清除動作。

參考文章:

1、 JVM內存:年輕代,老年代,永久代

2、 JVM內存區域劃分Eden Space、Survivor Space、Tenured Gen,Perm Gen解釋 (很形象的解釋)

JVM內存:年輕代、老年代、永久代(推薦 轉)