天天看點

JVM GC原理深度解析及性能調優實戰(二)

先看下拓撲圖

JVM GC原理深度解析及性能調優實戰(二)

Java堆從GC的角度還可以細分為: 新生代(Eden區、From Survivor區和To Survivor區)和老年代。

JVM GC原理深度解析及性能調優實戰(二)

新生代:分三個區:一個Eden區,兩個Survivor區(一般而言),大部分對象在Eden區中生成。當Eden區滿時,還存活的對象将被複制到兩個Survivor區(中的一個)。當這個Survivor區滿時,此區的存活且不滿足“晉升”條件的對象将被複制到另外一個Survivor區。對象每經曆一次Minor GC,年齡加1,達到“晉升年齡門檻值”後,被放到老年代,這個過程也稱為“晉升”。顯然,“晉升年齡門檻值”的大小直接影響着對象在新生代中的停留時間,在Serial和ParNew GC兩種回收器中,“晉升年齡門檻值”通過參數MaxTenuringThreshold設定,預設值為15。

Eden區:Java新對象的出生地(如果新建立的對象占用記憶體很大,則直接配置設定到老年代)。當Eden區記憶體不夠的時候就會觸發MinorGC,對新生代區進行一次垃圾回收。

ServivorFrom:上一次GC的幸存者,作為這一次GC的被掃描者。

ServivorTo:保留了一次MinorGC過程中的幸存者。

老年代:主要存放應用程式中生命周期長的記憶體對象。

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

MajorGC采用标記清除算法:首先掃描一次所有老年代,标記出存活的對象,然後回收沒有标記的對象。MajorGC的耗時比較長,因為要掃描再回收。MajorGC會産生記憶體碎片,為了減少記憶體損耗,我們一般需要進行合并或者标記出來友善下次直接配置設定。當老年代也滿了裝不下的時候,就會抛出OOM(Out of Memory)異常。

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

簡單描述下的gc 過程是這樣的:

JVM GC原理深度解析及性能調優實戰(二)

1、現在有一個新對象産生,那麼對象一定需要記憶體空間,于是現在需要為該對象進行記憶體空間的申請。

2、首先會判斷伊甸園區是否有記憶體空間,如果此時有充足記憶體空間,則直接将新對象儲存到伊甸園區。

3、但是如果此時伊甸園區的記憶體空間不足,那麼會自動執行Minor GC操作,将伊甸園區無用的記憶體空間進行清理。清理之後會繼續判斷伊甸園區空間是否充足?如果充足,則将新的對象直接在伊甸園區進行記憶體空間配置設定。

4、如果執行Minor GC之後伊甸園區空間依然不足,那麼這個時候會進行存活區判斷,如果存活區有剩餘空間,則将伊甸園區的部分活躍對象儲存在存活區,随後繼續判斷伊甸園區的記憶體空間是否充足,如果充足,則進行記憶體空間配置設定。

5、如果此時存活區也沒有記憶體空間了,則繼續判斷老年區,如果此時老年區的空間充足,則将存活區中的活躍對象儲存到老年區,而後存活區應付出現空餘空間,随後伊甸園區将部分活躍對象儲存地存活區中,最後在伊甸園區為新對象配置設定記憶體空間。

6、如果這個時候老年代記憶體空間也滿了,那麼這個時候将産生Major GC(Full GC)。然後再将存活區中的活躍對象儲存到老年區,進而騰出空間,然後再将伊甸園區的部分活躍對象儲存到存活區,最後在伊甸園區為新對象配置設定記憶體空間。

7、如果老年代執行Full GC之後依然空間依然不足,應付産生OOM(OutOfMemoryError)異常。

記憶體大小最大設定為10M,友善觀察,結果:

可以看到年輕代空間不足觸發Minor GC,多次Minor GC後空間仍然不足會觸發老年代的空間回收,老年代空間配置設定失敗會觸發Full GC,多次Full GC之後空間仍然不足就會導緻“OutOfMemoryErroy”。