第三章:JVM斷定哪些對象可回收

 

①引用計數算法

原理:給對象添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;在任什麼時候刻計數器的值爲0的對象就是不可能再被使用的,也就是可被回收的對象。web

它有一個致命的缺陷,那就是它沒法解決對象之間相互循環引用的的問題,對於循環引用的對象它沒法進行回收。算法

public class Object {

public Object instance;

public static void main(String[] args) {

// 1
Object objectA = new Object();
Object objectB = new Object();

// 2
objectA.instance = objectB;
objectB.instance = objectA;

// 3
objectA = null;
objectB = null;

}
}

 

 

程序啓動後,objectA和objectB兩個對象被建立並在堆中分配內存,這兩個對象都相互持有對方的引用,除此以外,這兩個對象再無任何其餘引用,實際上這兩個對象已經不可能再被訪問(引用被置空,沒法訪問),可是它們由於相互引用着對方,致使它們的引用計數器都不爲0,因而引用計數算法沒法通知GC收集器回收它們。spa

實際上,當第1步執行時,兩個對象的引用計數器值都爲1;當第2步執行時,兩個對象的引用計數器都爲2;當第3步執行時,兩者都清爲空值,引用計數器值都變爲1。根據引用計數算法的思想,值不爲0的對象被認爲是存活的,不會被回收;而事實上這兩個對象已經不可能再被訪問了,應該被回收。線程

 

 

②可達性分析算法

主流的JVM中,都是經過可達性分析算法來斷定對象是否存活的。code

可達性分析算法的基本思想是:經過一系列被稱爲"GC Roots"的對象做爲起始點,從這些節點開始向下搜索,搜索走過的路徑稱爲引用鏈,當一個對象到GC Roots對象沒有任何引用鏈相連,就認爲GC Roots到這個對象是不可達的,斷定此對象爲不可用對象,能夠被回收。orm

 

在上圖中1234可達的,不會被回收;567它們將會被斷定爲是可回收的對象。對象

 

在Java中,可做爲GC Roots的對象包括下面幾種:blog

一、虛擬機棧中引用的對象;接口

二、方法區中類靜態屬性引用的對象;內存

三、方法區中常量引用的對象;

四、本地方法棧中Native方法引用的對象。

 

③GC Roots對象
在 Java 語言中,可做爲 GC Root 的對象包括如下4種:
  • 虛擬機棧(棧幀中的本地變量表)中引用的對象
  • 方法區中類靜態屬性引用的對象
  • 方法區中常量引用的對象
  • 本地方法棧中 JNI(即通常說的 Native 方法)引用的對象

 

★ 虛擬機棧(棧幀中的本地變量表)中引用的對象此時的 s,即爲 GC Root,當s置空時,localParameter 對象也斷掉了與 GC Root 的引用鏈,將被回收。

public class StackLocalParameter {

   public StackLocalParameter(String name){}

}

public static void testGC(){

   StackLocalParameter s = new StackLocalParameter("localParameter");

   s = null;

}

★ 方法區中類靜態屬性引用的對象
s 爲 GC Root,s 置爲 null,通過 GC 後,s 所指向的 properties 對象因爲沒法與 GC Root 創建關係被回收。而 m 做爲類的靜態屬性,也屬於 GC Root,parameter 對象依然與 GC root 創建着鏈接,因此此時 parameter 對象並不會被回收。

public class MethodAreaStaicProperties {

   public static MethodAreaStaicProperties m;

   public MethodAreaStaicProperties(String name){}

}

public static void testGC(){

   MethodAreaStaicProperties s = new MethodAreaStaicProperties("properties");

   s.m = new MethodAreaStaicProperties("parameter");

   s = null;

}

★ 方法區中常量引用的對象m 即爲方法區中的常量引用,也爲 GC Root,s 置爲 null 後,final 對象也不會因沒有與 GC Root 創建聯繫而被回收。

public class MethodAreaStaicProperties {

   public static final MethodAreaStaicProperties m = MethodAreaStaicProperties("final");

   public MethodAreaStaicProperties(String name){}

}

public static void testGC(){

   MethodAreaStaicProperties s = new MethodAreaStaicProperties("staticProperties");

   s = null;

}

★  本地方法棧中引用的對象
任何 Native 接口都會使用某種本地方法棧,實現的本地方法接口是使用 C 鏈接模型的話,那麼它的本地方法棧就是 C 棧。當線程調用 Java 方法時,虛擬機會建立一個新的棧幀並壓入 Java 棧。然而當它調用的是本地方法時,虛擬機會保持 Java 棧不變,再也不在線程的 Java 棧中壓入新的幀,虛擬機只是簡單地動態鏈接並直接調用指定的本地方法。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章
相關標籤/搜索