天天看點

weak reference的介紹

對象回收條件:

在Java裡, 當一個對象o被建立時, 它被放在堆裡. 當GC運作的時候, 如果發現沒有任何引用指向o, o就會被回收. 也可以這麼了解, 一個對象被回收, 必須滿足兩個條件: 1)沒有任何引用指向它 2)GC被運作.

置空處理:

在現實情況寫代碼的時候, 我們往往通過把所有指向某個對象的引用置空來保證這個對象在下次GC運作的時候被回收

例如:

Object c = new Car();

c=null;

但是, 手動置空對象對于程式員來說, 是一件繁瑣且違背自動回收的理念的.  對于簡單的情況, 手動置空是不需要程式員來做的, 因為在java中, 對于簡單對象, 當調用它的方法執行完畢後, 指向它的引用會被從stack中彈出, 是以他就能在下一次GC執行時被回收了.

但是, 也有特殊例外. 當使用cache的時候, 由于cache的對象正是程式運作需要的, 那麼隻要程式正在運作, cache中的引用就不會被GC給(或者說, cache中的reference擁有了和主程式一樣的life cycle). 那麼随着cache中的reference越來越多, GC無法回收的object也越來越多, 無法被自動回收. 當這些object需要被回收時, 回收這些object的任務隻有交給程式編寫者了. 然而這卻違背了GC的本質(自動回收可以回收的objects).

weakreference的由來:

因為上面的原因, java中引入了weak reference(弱引用). 相對于前面舉例中的strong reference(強引用):Object c = new Car(); //隻要c還指向car對象, car對象就不會被回收

但是 當一個對象僅僅被weak reference指向, 而沒有任何其他strong reference指向的時候, 如果GC運作, 那麼這個對象就會被回收.

weakreference的使用:

WeakReference<Car> weakCar = newWeakReference(Car)(car);

 當要獲得weak reference引用的object時, 首先需要判斷它是否已經被回收:

weakCar.get();

 如果此方法為空, 那麼說明weakCar指向的對象已經被回收了.

可回收例子:

package weakreference;

public class Car {

  privatedouble price;

  privateString colour;

  publicCar(double price, String colour){

    this.price= price;

    this.colour= colour;

  }

  publicdouble getPrice() {

    returnprice;

  }

  publicvoid setPrice(double price) {

    this.price= price;

  }

  publicString getColour() {

    returncolour;

  }

  publicvoid setColour(String colour) {

    this.colour= colour;

  }

  publicString toString(){

    returncolour +"car costs $"+price;

  }

}

package weakreference;

import java.lang.ref.WeakReference;

public class TestWeakReference {

  publicstatic void main(String[] args) {

    Carcar = new Car(22000,"silver");

    WeakReference<Car>weakCar = new WeakReference<Car>(car);

    inti=0;

    while(true){

     if(weakCar.get()!=null){

       i++;

       System.out.println("Object is alive for "+i+" loops -"+weakCar);

     }else{

       System.out.println("Object has been collected.");

       break;

     }

    }

  }

}

在上例中, 程式運作一段時間後, 程式列印出"Object has been collected." 說明, weakreference指向的對象的被回收了.

值得注意的一點 , 即使有 car 引用指向對象, 且 car 是一個strong reference, weak reference weakCar指向的對象仍然被回收了. 這是因為java的編譯器在發現進入while循環之後, car 已經沒有被使用了, 是以進行了優化(将其置空?).

不可回收例子:

當把TestWeakReference.java修改為:

package weakreference;

import java.lang.ref.WeakReference;

public class TestWeakReference {

  publicstatic void main(String[] args) {

    Carcar = new Car(22000,"silver");

    WeakReference<Car>weakCar = new WeakReference<Car>(car);

    inti=0;

    while(true){

     System.out.println("here is the strong reference 'car' "+car);

     if(weakCar.get()!=null){

       i++;

       System.out.println("Object is alive for "+i+" loops -"+weakCar);

     }else{

       System.out.println("Object has been collected.");

       break;

     }

    }

  }

}

 weak reference指向的object就不會被回收了. 因為還有一個strongreference car 指向它. WeakReference的一個特點是它何時被回收是不可确定的, 因為這是由GC運作的不确定性所确定的. 是以, 一般用weak reference引用的對象是:有價值被緩存, 而且很容易被重新被建構, 且很消耗記憶體的對象.

ReferenceQueue的簡單了解:

在weak reference指向的對象被回收後, weak reference本身其實也就沒有用了. java提供了一個ReferenceQueue來儲存這些所指向的對象已經被回收的reference. 用法是在定義WeakReference的時候将一個ReferenceQueue的對象作為參數傳入構造函數.

其他類型的references

SoftReference簡單了解:

soft reference(軟引用)和weakreference一樣, 但被GC回收的時候需要多一個條件: 當系統記憶體不足時, soft reference指向的object才會被回收. 正因為有這個特性, soft reference比weak reference更加适合做cache objects的reference. 因為它可以盡可能的retain cached objects, 減少重建他們所需的時間和消耗.

總之:

對象被回收條件:1)沒有任何引用指向它 2)GC被運作.

soft reference和weakreference,可以幫助我們更好的進行對象的回收。

繼續閱讀