誰纔是真正的垃圾:判斷對象的可觸及性

垃圾回收的基本思想是考察每個對象的可觸及性,即從根節點開始是否能夠訪問到這個對象,若是能夠,則說明當前對象正在被使用,若是從全部的根節點都沒法訪問到某個對象,說明該對象已經再也不使用了,通常來講,此對象符合垃圾回收的條件。可是,一個沒法觸及的對象有可能在某個條件下復活本身,若是這樣,那麼對它的回收就是不合理的,爲此,須要給出一個可觸及性狀態的定義,並規定在什麼狀態下,才能夠安全的回收對象。安全

可觸及的包括3種狀態:jvm

  • 可觸及的:從根節點開始,能夠到達這個對象;
  • 可復活的:對象的全部引用都被釋放,可是對象有可能在finalize()函數中復活;
  • 不可觸及的:對象的finalize()函數被調用,而且沒有復活,那麼就會進入不可觸及狀態,不可觸及的對象不可能被複活,由於finalize()函數只會被調用一次。

以上3種狀態,只有在對象不可觸及時才能夠被回收。ide

1 對象的復活函數

實例1 :前面提到,對象可能在finalize()函數中復活本身,這裏給出一個實例。this

package com.jvm;
public class CanReliveObj {
  public static CanReliveObj obj ;
  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    System.out.println("CanReliveObj finalize called");
    obj = this;
  }
  @Override
  public String toString() {
    return "CanReliveObj";
  }

  public static void main(String[] args) throws InterruptedException {
    obj = new CanReliveObj();
    obj = null;
    System.gc();
    Thread.sleep(1000);
    if(obj==null){
      System.out.println("obj is null");
    }else{
      System.out.println("obj 可用");
    }
    System.out.println("第二次GC");
    obj = null;
    System.gc();
    Thread.sleep(1000);
    if(obj==null){
      System.out.println("obj is null");
    }else{
      System.out.println("obj 可用");
    }
  }
}對象

運行代碼打印:資源

CanReliveObj finalize called
obj 可用
第二次GC
obj is nullio

能夠看出,在第一次將obj置爲null後,進行GC,結果發現obj對象被複活了。等到第二次再釋放對象引用並運行GC,對象才真正被回收。這是由於第一次GC時,在finalize()函數調用以前,雖然系統中的引用已經被清除,可是在實例方法finalize()中,對象的引用this依然被傳入方法內部,致使引用外泄,對象復活,此時對象又變成可觸及狀態。因爲finalize()函數只會被調用一次,所以,在第二次清除釋放對象的引用時,對象就再無機會復活,所以會被回收。class

注意:垃圾回收

finalize()函數是一個糟糕的應用模式,不推薦使用finalize()函數釋放資源。

由於:其一,finalize()函數有可能發生引用外泄,在無心間復活對象

        其二,因爲finalize()是被系統調用的,調用時間是不明確的,所以不是一個好的資源釋放方案,推薦使用try-catch-finally語句進行資源的釋放。

相關文章
相關標籤/搜索