天天看點

【轉】Java中的新生代、老年代、永久代和各種GC新生代老年代永久代

【轉】Java中的新生代、老年代、永久代和各種GC

  • 新生代
  • 老年代
  • 永久代
【轉】Java中的新生代、老年代、永久代和各種GC新生代老年代永久代

JVM中的堆,一般分為三大部分:新生代、老年代、永久代:

新生代

主要是用來存放新生的對象。一般占據堆的1/3空間。由于頻繁建立對象,是以新生代會頻繁觸發MinorGC進行垃圾回收。

新生代又分為 Eden區、ServivorFrom、ServivorTo三個區。

  • Eden區:Java新對象的出生地(如果新建立的對象占用記憶體很大,則直接配置設定到老年代)。當Eden區記憶體不夠的時候就會觸發MinorGC,對新生代區進行一次垃圾回收。
  • ServivorTo:保留了一次MinorGC過程中的幸存者。
  • ServivorFrom:上一次GC的幸存者,作為這一次GC的被掃描者。

    當JVM無法為建立對象配置設定記憶體空間的時候(Eden滿了),Minor GC被觸發。是以新生代空間占用率越高,Minor GC越頻繁。

MinorGC的過程:采用複制算法。

  1. 首先,把Eden和ServivorFrom區域中存活的對象複制到ServicorTo區域(如果有對象的年齡以及達到了老年的标準,一般是15,則指派到老年代區)
  2. 同時把這些對象的年齡+1(如果ServicorTo不夠位置了就放到老年區)
  3. 然後,清空Eden和ServicorFrom中的對象;最後,ServicorTo和ServicorFrom互換,原ServicorTo成為下一次GC時的ServicorFrom區。
    【轉】Java中的新生代、老年代、永久代和各種GC新生代老年代永久代

老年代

老年代的對象比較穩定,是以MajorGC不會頻繁執行。

在進行MajorGC前一般都先進行了一次MinorGC,使得有新生代的對象晉身入老年代,導緻空間不夠用時才觸發。當無法找到足夠大的連續空間配置設定給新建立的較大對象時也會提前觸發一次MajorGC進行垃圾回收騰出空間。

MajorGC采用标記—清除算法:

  1. 首先掃描一次所有老年代,标記出存活的對象
  2. 然後回收沒有标記的對象。

MajorGC的耗時比較長,因為要掃描再回收。MajorGC會産生記憶體碎片,為了減少記憶體損耗,我們一般需要進行合并或者标記出來友善下次直接配置設定。

當老年代也滿了裝不下的時候,就會抛出OOM(Out of Memory)異常。

永久代

指記憶體的永久儲存區域,主要存放Class和Meta(中繼資料)的資訊。

Class在被加載的時候被放入永久區域。它和和存放執行個體的區域不同,GC不會在主程式運作期對永久區域進行清理。是以這也導緻了永久代的區域會随着加載的Class的增多而脹滿,最終抛出OOM異常。

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

元空間的本質和永久代類似,都是對JVM規範中方法區的實作。不過元空間與永久代之間最大的差別在于:元空間并不在虛拟機中,而是使用本地記憶體。是以,預設情況下,元空間的大小僅受本地記憶體限制。類的中繼資料放入 native memory, 字元串池和類的靜态變量放入java堆中. 這樣可以加載多少類的中繼資料就不再由MaxPermSize控制, 而由系統的實際可用空間來控制。

  • Major GC和Full GC差別
  • Full GC:收集young gen、old gen、perm gen
  • Major GC:有時又叫old gc,隻收集old gen

Minor GC觸發機制:

  當年輕代滿時就會觸發Minor GC,這裡的年輕代滿指的是Eden代滿,Survivor滿不會引發GC。通過複制算法,回收垃圾。複制算法不會産生記憶體碎片。

複制算法将記憶體劃分為兩個區間,在任意時間點,所有動态配置設定的對象都隻能配置設定在其中一個區間(稱為活動區間),而另外一個區間(稱為空閑區間)則是空閑的。

當有效記憶體空間耗盡時,JVM将暫停程式運作,開啟複制算法GC線程。接下來GC線程會将活動區間内的存活對象,全部複制到空閑區間,且嚴格按照記憶體位址依次排列,與此同時,GC線程将更新存活對象的記憶體引用位址指向新的記憶體位址。

此時,空閑區間已經與活動區間交換,而垃圾對象現在已經全部留在了原來的活動區間,也就是現在的空閑區間。事實上,在活動區間轉換為空間區間的同時,垃圾對象已經被一次性全部回收。

【轉】Java中的新生代、老年代、永久代和各種GC新生代老年代永久代

Major GC的觸發機制:

Major GC又稱為Full GC。當年老代空間不夠用的時候,虛拟機會使用“标記—清除”或者“标記—整理”算法清理出連續的記憶體空間,配置設定對象使用。

【轉】Java中的新生代、老年代、永久代和各種GC新生代老年代永久代

Full GC觸發機制:

  (1)調用System.gc時,系統建議執行Full GC,但是不必然執行

  (2)老年代空間不足

  (3)方法區空間不足

  (4)通過Minor GC後進入老年代的平均大小大于老年代的可用記憶體

  (5)由Eden區、survivor space1(From Space)區向survivor space2(To Space)區複制時,對象大小大于To Space可用記憶體,則把該對象轉存到老年代,且老年代的可用記憶體小于該對象大小

    當永久代滿時也會引發Full GC,會導緻Class、Method元資訊的解除安裝。

虛拟機給每個對象定義了一個對象年齡(Age)計數器。如果對象在 Eden 出生并經過第一次 Minor GC 後仍然存活,并且能被 Survivor 容納的話,将被移動到 Survivor 空間中,并将對象年齡設為 1。對象在 Survivor 區中每熬過一次 Minor GC,年齡就增加 1 歲,  當它的年齡增加到一定程度(預設為 15 歲)時,就會被晉升到老年代中。對象晉升老年代的年齡門檻值,可以通過參數 -XX:MaxTenuringThreshold (門檻值)來設定。