JVM學習--垃圾收集器判斷物件存活方法
阿新 • • 發佈:2018-11-10
文章目錄
JVM學習–垃圾收集器判斷物件存活方法
相比於C++,Java的優點之一就是會對無用的物件進行垃圾回收,減少記憶體溢位的概率。在進行垃圾回收之前,需要判斷物件是否還存活,也就是是否還被引用。
public class Demo{
public static void func(){
Object obj =new Object();
}
public static void main (String[] args){
......
func();
.......
}
}
當func()執行完,obj引用不存在,該引用指向堆中的物件沒有被引用,但是仍然佔用堆的記憶體空間,那麼合適的時候,虛擬機器會將其進行回收。
目前常用的有兩種判斷方法,第一種是引用技術法,第二種是可達性分析演算法。
引用計數法
引用計數法就是設定一個初始值為0的計數器,當物件被引用時,計數器加1,當物件去除引用時,計數器減1.當執行垃圾回收時,如果該物件的引用計數值為0。,可以判斷該物件不被使用,可以進行垃圾回收。
引用計數法效率高,但是存在相互迴圈引用時,會出現計數值不為零的情況。主流的虛擬機器不會選用該演算法。
如下的相互迴圈引用的例子, refA = null; refB = null;後,仍有引用引用AB兩個物件,因此它們的計數器的值仍然為1,如果使用引用計數法,這兩個物件是無法回收的。
public class RefCountGC {
private String name;
RefCountGC ref;
public RefCountGC(String name) {
this.name = name;
}
public void setRef(RefCountGC ref) {
this.ref = ref;
}
public static void main(String[] args) {
//第1步,物件A計數器+1 = 1
RefCountGC refA = new RefCountGC("A");
//第2步,物件B計數器+1 = 1
RefCountGC refB = new RefCountGC("B");
//第3步,物件B計數器+1 = 2
refA.setRef(refB);
//第4步,物件A計數器+1 = 2
refB.setRef(refA);
//第5步,物件A計數器-1 = 1
refA = null;
//第6步,物件B計數器-1 = 1
refB = null;
System.gc();
}
}
可達性分析演算法。
在主流的商用程式語言中(Java和C#),都是使用可達性分析演算法判斷物件是否存活的。這個演算法的基本思路就是通過一系列名為GC Root的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈(Reference Chain),當一個物件到GC Roots沒有任何引用鏈相連時,則證明此物件是不可用的,上圖物件object4, object5, object6雖然有互相關聯,但它們到GC Roots是不可達的,所以它們將會判定為是可回收物件。
那麼那些點可以作為GC Roots呢?一般來說,如下情況的物件可以作為GC Roots:
- 虛擬機器棧(棧楨中的本地變量表)中的引用的物件
- 方法區中的類靜態屬性引用的物件
- 方法區中的常量引用的物件
- 本地方法棧中JNI(Native方法)的引用的物件