天天看點

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

垃圾收集算法

  1. 标記清除算法

    标記清除算法分為标記,清除兩個步驟,首先标記算法對可回收的對象進行标記,然後垃圾收集器根據标記清除相應的内容。

    不是說将記憶體空間的位元組清零,而是記錄下這段記憶體的真實結束位址,下一次配置設定記憶體的時候,會直接覆寫這段記憶體。

    标記清除算法是最基礎的算法,後續收集算法大多都是标記清除算法為基礎的,對其缺點進行改進的

    主要有兩個缺點:

    • 執行效率不穩定,如果Java堆中包含大量對象,并且其中大部分是需要被回收的,這時必須進行大量标記和清除的動作,導緻标記和清除兩個過程會的執行效率對随着數量增長而降低;
    • 記憶體碎片化問題,标記和清除會産生大量不連續的記憶體碎片,空間碎片太多可能會導緻以後在程式運作過程中需要配置設定較大對象時無法找到足夠的連續記憶體而不得不提前觸發另一次垃圾收集動作。
  2. 标記整理算法

    标記整理算法與标記清除算法的标記過程一樣,隻是後續步驟不是直接對可回收對象進行清理而是将所有存活對象向記憶體空間一端移動然後清理掉邊界以外的記憶體

    Java記憶體回收(二)垃圾收集算法、分代垃圾回收
  3. 标記複制算法

    标記複制算法簡稱為複制算法,為了解決标記清除算法面對大量可回收對象時執行效率低的問題,提出了“半區複制”的垃圾收集算法:将可用記憶體按容量分為大小相等的兩塊,每次隻是用其中的一塊,當這一塊記憶體用完了,就将還存活的對象複制到另外一塊上面,然後再把已使用的記憶體空間一次清理掉。如果記憶體中多數的對象是存活的,就會造成大量的記憶體間複制的開銷;但這樣可以避免造成記憶體碎片的問題。

分代垃圾回收

目前商業虛拟機的垃圾收集器,大多數都遵循了“分代收集”的理論進行設計,分代收集名為理論,實質是一套符合大多數程式運作實際情況的經驗法則,它建立在兩個分代假說之上:

  • 弱分代假說:絕大多數對象都是朝生夕滅的。
  • 強分代假說:熬過越多次垃圾收集過程的對象就越難以消亡。

這兩個分代假說奠定了多款常用的垃圾收集器的一緻的設計原則:收集器應該将Java堆劃分出不同的區域,然後将回收對象依據其年齡配置設定到不同的區域中存儲。

如果一個區域中大多數對象都是朝生夕滅的,難以熬過垃圾收集過程的話,那麼把它們集中在一起,每次回收時隻關注如何保留少量存活而不是去标記那些大量将要被回收的對象,就能以較低代價回收到大量的空間;如果剩下的都是難以消亡的對象,那把它們集中放到一起,虛拟機便可以使用較低的頻率來回收這個區域,這就同時兼顧了垃圾收集的時間開銷和記憶體的空間有效利用。

Java對劃分出不同的區域之後垃圾收集器才可以每次隻回收其種某一個或者某些部分的區域,因而有了“Minor GC"、“Major Gc”、"Full GC"這樣的回收類型的劃分;也才能針對不同的區域安排與裡面存儲對象存亡特征相比對的垃圾收集算法,因而發展出了”标記清除算法“,”标記整理算法“,”标記複制算法“。

回收流程:

長時間使用的對象放在老年代中(長時間回收一次,回收話費時間舊),用完即可丢棄的對象放在新生代中(頻繁需要回收,回收速度相對較快)

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

新建立的對象都放在了新生代的eden區

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

當eden區無法在放入新建立的對象時就會觸發一次Minor GC,Minor GC會将eden區和幸存區from仍需要存活的對象先複制到幸存區to中,并将其壽命加一,在交換from和to。

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

将eden存活的對象複制到to區,清理掉eden中剩餘的對象

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

交換from和to

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

繼續向eden中添加對象,當第二次進行Minor GC時,将eden區和from中存活的對象複制到to,然後交換from和to,下圖from區中1代表從eden複制過來的對象,2代表上一步在from中這次經過垃圾回收人存活的對象其壽命再加一。

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

當幸存區某個對象的壽命超過某個門檻值就會被放入老年代中

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

如果新生代老年代中的記憶體都滿了就會先進行一次Minor GC,在進行一次Full GC,掃描新生代和老年代中所有不在存活的對象進行回收。

Java記憶體回收(二)垃圾收集算法、分代垃圾回收

小結:

  • 新建立的對象首先會被配置設定在伊甸園區域。
  • 新生代空間不足時,觸發Minor GC,伊甸園和 FROM幸存區需要存活的對象會被COPY到TO幸存區中,存活的對象壽命+1,并且交換FROM和TO。
  • Minor GC會引發 Stop The World:暫停其他使用者的線程,等待垃圾回收結束後,使用者線程才可以恢複執行。
  • 當對象壽命超過門檻值15時,會晉升至老年代。
  • 如果新生代、老年代中的記憶體都滿了,就會先觸發Minor GC,再觸發Full GC,掃描新生代和老年代中所有不再使用的對象并回收。

參考文章:

深入了解Java虛拟機

JVM_04 垃圾回收機制_興趣使然的草帽路飛-CSDN部落格_jvm垃圾回收機制