1. 程式人生 > >JVM學習--垃圾收集器判斷物件存活方法

JVM學習--垃圾收集器判斷物件存活方法

JVM學習–總索引

文章目錄

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方法)的引用的物件