JVM垃圾回收——新生代,老年代,永久代,Minor GC,Full GC

ChenjcarryOn發表於2020-03-21

參考資料:

  1. 《深入理解Java虛擬機器》——周志明
  2. https://blog.csdn.net/u010796790/article/details/52213708
  3. https://blog.csdn.net/lirenzuo/article/details/77749925
  4. https://www.cnblogs.com/ygj0930/p/6522828.html

周志明先生,在《深入理解Java虛擬機器》一書中曾提到:程式計數器,虛擬機器棧,本地方法棧這3個區域是執行緒私有的,隨執行緒而生,隨執行緒而滅,這幾個區域就不需要過多考慮回收的問題,因為方法結束或者執行緒結束時,記憶體就自然跟著回收了。主要討論Java堆和方法區的回收。(Java堆和方法區是《Java虛擬機器規範》的術語)

Java堆通常分為新生代,老年代。永久代,實際上就是方法區。

【方法區】是JVM的一種規範,存放類資訊,常量,靜態變數,即時編譯後的程式碼等。

【永久代】是HotSpot的一種具體實現,實際上指的就是方法區,或者說用永久代來實現方法區。對於其他虛擬機器來說是不存在永久代的概念的。

新生代:

對於新生代而言,無論是使用哪一種垃圾收集器(JDK1.6之前新生代的垃圾收集器有三種:Serial,ParNew,Parallel Scavenge)採用的都是複製收集演算法

JDK1.6中,新生代與老年代的比例的值為 1:2 ( 該值可以通過引數 –XX:NewRatio 來指定 ),新生代又可細分為:EdenFrom SurvivorTo Survivor三個區(811),也就是說新生代中可用記憶體空間為整個新生代容量的90%,有10%的記憶體被浪費。

Eden:新物件的出生地。
From Survivor上一次GC的倖存者,作為這一次GC的被掃描者。
To Survivor保留MinorGC過程中的倖存者。

MinorGC的觸發條件】Eden區記憶體不足的時候,虛擬機器將進行一次MinorGCSurvivor區記憶體不足不會觸發MinorGCMinorGC之後,可能會與一些新生代的物件年齡滿足進入老年代,老年代的佔用會有所升高。

MinorGC的過程MinorGC採用複製演算法。首先,把EdenFrom Survivor區域中存活的物件複製到To Survivor區域,同時把這些物件的年齡+1(預設情況下15歲就直接送到老年代了,晉升老年代的閾值可以通過-XX:MaxTenuringThreshold設定);然後,清空EdenFrom Survivor中的物件;最後,To SurvivorFrom Survivor互換,原To Survivor成為下一次GC時的From Survivor區。

老年代:

主要存放程式中年齡較大和需要佔用大量連續記憶體空間的物件。老年代的物件比較穩定,所以MajorGC/Full GC執行的頻率較低。一般都是在空間不足的時候才會執行MajorGC/Full GC。

JDK1.6之前老年代的垃圾收集器Serial Old,Parallel Old採用的是標記—整理演算法,CMS採用的標記—清除演算法。標記—清除演算法會產生大量的記憶體碎片。

【新生代的物件進入老年代的情況】:

  1. 設定了-XX:PretenureSizeThreshold3M 引數,那麼大於3M的物件就會直接就進入老年代,這樣做的目的是避免在Eden區以及兩個Survivor區之間發生大量的記憶體複製。(只對於Serial收集器和ParNew兩款收集器有效)
  2. 長期存活的物件將進入老年代:對於在Survivor區中每熬過一次Minor GC,年齡就增加1歲,當它的年齡增加到一定程度,就會晉升到老年代中。(預設15歲,可以通過-XX:MaxTenuringThreshold設定)
  3. 如果在Survivor空間中相同年齡所有物件物件大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的物件就可以直接進入老年代,無須等到MaxTenuringThreshold要求的年齡。
  4. 空間分配擔保機制:當Minor GC時,新生代存活的物件大於Survivor的大小時,這時一個Survivor裝不下它們,那麼它們就會進入老年代。

永久代:

HotSpot中對於JVM規範中方法區的實現,指記憶體的永久儲存區域,主要存放Class和Meta(後設資料)的資訊,Class在被載入的時候被放入永久區域。

在Java8中,永久代已經被移除,被一個稱為“後設資料區”(元空間)的區域所取代。

元空間的本質和永久代類似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機器中,而是使用本地記憶體

Full GC:

         關於Major GC,如果我們簡單理解的話,Major GC和Full GC通常情況下可以認為是等價的。主要是發生在老年代GC,出現Major GC/Full GC,通常情況下伴隨著至少一次的Minor GC(並不是絕對的),Major GC/Full GC的速度一般比Minor GC慢10倍以上。

【Full GC的觸發條件】:

  1. 當準備要觸發一次Minor GC時,如果發現統計資料說之前Minor GC的平均晉升大小比目前老年代剩餘的空間大,則不會觸發Minor GC而是轉為觸發Full GC(因為HotSpot VM的GC裡,除了CMS的concurrent collection之外,其它能收集老年代的GC都會同時收集整個GC堆,包括新時代,所以不需要事先觸發一次單獨的Minor GC);
  2. 如果有永久代的話,要在永久代分配空間但已經沒有足夠空間時,也要觸發一次Full GC;(Java虛擬規範中並不要求虛擬機器在方法區實現垃圾收集,而且在方法區中進行垃圾收集的“價效比”較低。在大量使用頻繁自定義ClassLoader的場景都需要虛擬機器具備類解除安裝的功能,以保證永久代不會溢位。)
  3. System.gc()、heap dump帶GC,預設也是觸發Full GC。

相關文章