天天看點

JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】

文章目錄

  • ​​思維導圖​​
  • ​​标記清除算法(其他算法的基礎)​​
  • ​​複制算法(新生代的GC)​​
  • ​​标記整理/壓縮算法(老年代的GC)​​
  • ​​标記-清除算法、複制算法、标記整理算法總結​​
  • ​​分代收集算法(新生代的GC+老年代的GC)​​

思維導圖

JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】

​​JVM-04垃圾收集Garbage Collection(上)【垃圾對象的判定】​​探讨了如何判定堆記憶體中的對象是否已經死亡,這裡我們來繼續讨論下JVM中常用的垃圾收集算法

标記清除算法(其他算法的基礎)

标記-清除算法是現代垃圾回收算法的思想基礎。标記-清除算法将垃圾回收分為兩個階段:标記階段和清除階段。一種可行的實作是,在标記階段,首先通過根節點,标記所有從根節點開始的可達對象。是以,未被标記的對象就是未被引用的垃圾對象;然後,在清除階段,清除所有未被标記的對象。

當堆中的有效記憶體空間(available memory)被耗盡的時候,就會停止整個程式(也被成為stop the world),然後進行兩項工作,第一項則是标記,第二項則是清除

标記:周遊所有的GC Roots,并将從GC Roots可達的對象設定為存活對象;

清除:周遊堆中的所有對象,将沒有被标記可達的對象清除;

也就是說,就是當程式運作期間,若可以使用的記憶體被耗盡的時候,GC線程就會被觸發并将程式暫停,随後将依舊存活的對象标記一遍,最終再将堆中所有沒被标記的對象全部清除掉,接下來便讓程式恢複運作。

JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】

優缺點:

  • 涉及大量的記憶體周遊工作,是以執行性能較低,這也會導緻“stop the world”時間較長,java程式吞吐量降低;
  • 對象被清除之後,被清除的對象留下記憶體的空缺位置,造成記憶體不連續,空間浪費。

複制算法(新生代的GC)

将現有的記憶體空間分為兩快,每次隻使用其中一塊,在垃圾回收時将正在使用的記憶體中的存活對象複制到未被使用的記憶體塊中,之後,清除正在使用的記憶體塊中的所有對象,交換兩個記憶體的角色,完成垃圾回收。

JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】

Java 堆記憶體并不需要按照1:1的比例劃分記憶體空間,而是将記憶體分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中的一塊Survivor。當回收時,将Eden和Survivor中還存活着的對象一次性地拷貝到另外一個Survivor空間上,最後清理掉Eden和剛才用過的Survivor的空間。

HotSpot虛拟機預設Eden:Survivor From ::Survivor To 的大小比例是8:1:1(可以通過-SurvivorRattio來配置),也就是每次新生代中可用記憶體空間為整個新生代容量的90%,隻有10%的記憶體會被“浪費”。

當然,98%的對象可回收隻是一般場景下的資料,我們沒有辦法保證回收都隻有不多于10%的對象存活,當Survivor空間不夠用時,需要依賴其他記憶體(這裡指老年代)進行配置設定擔保。

JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】

優缺點:

複制算法相對标記壓縮算法來說更簡潔高效,但它的缺點也顯而易見,它不适合用于存活對象多的情況,因為那樣需要複制的對象很多,複制性能較差,是以複制算法往往用于記憶體空間中新生代的垃圾回收,因為新生代中存活對象較少,複制成本較低。它另外一個缺點是記憶體空間占用成本高,因為它基于兩份記憶體空間做對象複制,在非垃圾回收的周期内隻用到了一份記憶體空間,記憶體使用率較低。

标記整理/壓縮算法(老年代的GC)

标記:它的第一個階段與标記/清除算法是一模一樣的,均是周遊GC Roots,然後将存活的對象标記。

整理:移動所有存活的對象,且按照記憶體位址次序依次排列,然後将末端記憶體位址以後的記憶體全部回收。是以,第二階段才稱為整理階段。

JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】

上圖中可以看到,标記的存活對象将會被整理,按照記憶體位址依次排列,而未被标記的記憶體會被清理掉。如此一來,當我們需要給新對象配置設定記憶體時,JVM隻需要持有一個記憶體的起始位址即可,這比維護一個空閑清單顯然少了許多開銷。

優點:

因為标記清除算法會造成記憶體的不連續,是以标記整理(壓縮)算在标記清除算法的基礎上,增加了整理過程,解決了标記清除算法記憶體不連續的問題。同時也消除了複制算法當中,記憶體減半的高額代價。

缺點:

标記整理(壓縮)也會産生“stop the world”,不能和java程式并發執行。在壓縮過程中一些對象記憶體位址會發生改變,java程式隻能等待壓縮完成後才能繼續。

标記-清除算法、複制算法、标記整理算法總結

在GC線程開啟時,或者說GC過程開始時,它們都要暫停應用程式(stop the world)。

它們的差別如下:(>表示前者要優于後者,=表示兩者效果一樣)

(1)效率:複制算法>标記/整理算法>标記/清除算法(此處的效率隻是簡單的對比時間複雜度,實際情況不一定如此)。

(2)記憶體整齊度:複制算法=标記/整理算法>标記/清除算法。

(3)記憶體使用率:标記/整理算法=标記/清除算法>複制算法。

  • 可以看到标記/清除算法是比較落後的算法了,但是後兩種算法卻是在此基礎上建立的。
  • 時間與空間不可兼得。

分代收集算法(新生代的GC+老年代的GC)

目前商業虛拟機都采用分代收集算法。

分代的垃圾回收政策,是基于這樣一個事實:不同的對象的生命周期是不一樣的。是以,不同生命周期的對象可以采取不同的收集方式,以便提高回收效率。

繼續閱讀