天天看點

JVM垃圾回收機制及垃圾回收算法一、如何判斷對象已經死亡?二、垃圾回收算法

垃圾回收

  • 一、如何判斷對象已經死亡?
  • 二、垃圾回收算法
    • 1.标記-清除算法
    • 2.複制算法
    • 3.标記-整理算法
    • 4. 分代回收理論

一、如何判斷對象已經死亡?

1. 引用計數法

給對象中添加一個引用計數器,每當有一個地方引用它,計數器就加 1;當引用失效,計數器就減 1;任何時候計數器為 0 的對象就是不可能再被使用的。

優缺點:簡單,效率高,但很難解決循環引用

2. 可達性分析

這個算法的基本思想就是通過一系列的稱為 “GC Roots” 的對象作為起點,從這些節點開始向下搜尋,節點所走過的路徑稱為引用鍊,當一個對象到 GC Roots 沒有任何引用鍊相連的話,則證明此對象是不可用的。

JVM垃圾回收機制及垃圾回收算法一、如何判斷對象已經死亡?二、垃圾回收算法

可作為 GC Roots 的對象包括下面幾種:

  • 虛拟機棧(棧幀中的本地變量表)中引用的對象
  • 本地方法棧(Native 方法)中引用的對象
  • 方法區中類靜态屬性引用的對象
  • 方法區中常量引用的對象
  • 所有被同步鎖持有的對象

二、垃圾回收算法

1.标記-清除算法

标記-清除算法将垃圾回收分為兩個階段:标記階段和清除階段。

在标記階段首先通過根節點(GC Roots),标記所有從根節點開始的對象,未被标記的對象就是未被引用的垃圾對象。然後,在清除階段,清除所有未被标記的對象。

JVM垃圾回收機制及垃圾回收算法一、如何判斷對象已經死亡?二、垃圾回收算法

适用場合:

  • 存活對象較多的情況下比較高效
  • 适用于年老代

缺點:

  • 效率問題:如果需要标記的對象太多,效率不高
  • 空間問題:标記清除後會産生大量不連續的碎片

2.複制算法

為了解決效率問題,“複制”收集算法出現了。它可以将記憶體分為大小相同的兩塊,每次使用其中的一塊。當這一塊的記憶體使用完後,就将還存活的對象複制到另一塊去,然後再把使用的空間一次清理掉。這樣就使每次的記憶體回收都是對記憶體區間的一半進行回收。具體過程如下圖所示:

JVM垃圾回收機制及垃圾回收算法一、如何判斷對象已經死亡?二、垃圾回收算法

适用場合:

  • 存活對象較少的情況下比較高效
  • 掃描了整個空間一次(标記存活對象并複制移動)
  • 适用于年輕代(即新生代):大部分對象是"朝生夕死"的,存活下來的會很少

缺點:

  • 隻能夠使用一半記憶體
  • 需要複制移動對象,如果存活對象很多,那麼Copying算法的效率将會大大降低

3.标記-整理算法

為了解決複制算法的缺陷,充分利用記憶體空間,提出了标記-整理算法。該算法标記階段和标記-清除一樣,但是在完成标記之後,它不是直接清理可回收對象,而是将存活對象都向一端移動,然後清理掉端邊界以外的記憶體。具體過程如下圖所示:

JVM垃圾回收機制及垃圾回收算法一、如何判斷對象已經死亡?二、垃圾回收算法

4. 分代回收理論

分代收集算法就是目前虛拟機使用的回收算法,它解決了标記整理不适用于老年代的問題,将記憶體分為各個年代。一般情況下将堆區劃分為老年代(Tenured Generation)和新生代(Young Generation),在堆區之外還有一個代就是永久代(Permanet Generation)。

在不同年代使用不同的算法,進而使用最合适的算法,新生代存活率低,可以使用複制算法。而老年代對象存活率高,沒有額外空間對它進行配置設定擔保,是以隻能使用标記清除或者标記整理算法。