我們知道,虛擬機器判斷一個物件是否“已死”,是判斷物件是否還有引用指向它。而虛擬機器又是如何判斷是否有引用指向物件呢?
目前,判斷物件是否存活的演算法有兩種:
- 引用計數演算法
- 可達性分析演算法
一、引用計數演算法
每個物件都有一個計數器,當這個物件被一個變數引用或者被另一個物件引用時,計數器值就加一,當引用失效時,計數器值就減1,當計數器為0時,則物件不可能再被使用,需要被回收。
二、可達性分析演算法
通過一系列稱為“GC Roots”的物件作為起始點,向下搜尋 走過的路徑稱為“引用鏈”,當一個物件到GC Roots 沒有任何引用鏈,即從GC roots 到這個物件不可達, 則證明物件不可用。
2.1 可以作為GC Roots的有哪些物件
- 虛擬機器棧區域性變數表中引用的物件
- 方法區中靜態變數引用的物件
- 方法區中常量引用的物件
- 本地方法棧中Native方法引用的物件
三、兩種方式對比
- 引用計數法雖然實現簡單,效率高,但是容易出現迴圈引用。
- 可達性分析演算法不存在迴圈引用問題,因此是主流的判別方法。
迴圈引用例子:
public class ReferenceCounting {
public Object data = null;
public static void test() {
ReferenceCounting objA = new ReferenceCounting();
ReferenceCounting objB = new ReferenceCounting();
objA.data = objB;
objB.data = objA;
objA = null;
objB = null;
}
}
複製程式碼
例子中objA和objB起初所指向的兩個物件已經沒有引用指向它們,但是因為成員變數都引用著對方,所以引用計數不為0,垃圾回收器無法回收。