對象的垃圾回收和四種引用

對象在內存中分爲三種狀態:緩存

可達狀態ide

一個對象建立之後,有一個或者多個引用變量引用該對象,那麼這個對象屬於可達狀態性能

 

可恢復狀態ui

若是程序中某個對象再也不有任何引用變量引用它,他將進入可恢復狀態,此時從有向圖的起始頂點不能導航到該對象。在這種狀態下,系統的垃圾回收機制轉變回收該對象所佔用的內存。在回收該對象以前,系統會調用可恢復狀態的對象的finalize方法進行資源清理,若是系統調用finalize方法從新讓一個以上的引用變量引用該對象,則該對象會再次變成可達狀態;不然,該對象將進入不可達狀態。this

 

 

不可達狀態spa

當對象的全部關聯都被切斷,且系統調用全部對象的finalize方法依然沒有使該對象變成可達狀態後,這個對象將永久性地失去引用,最後變成不可達狀態。只有當一個對象出於不可達狀態,系統纔會真正回收該對象所佔用的資源。.net

 

對象狀態轉化圖線程

finalize方法指針

垃圾回收對象內存以前會先調用finalize方法,這個是object中的方法,注意有可能失去引用的某個對象只是佔了少許內存,並且系統也沒有嚴重內存需求,所以垃圾回收機制沒有試圖回收該對象佔用資源,因此finalize方法也不會執行。code

protected void finalize() throws Throwable 

有以下幾個特色:

1 不要主動調用某個對象的finalize方法,應該由垃圾回收機制調用。

2  finalize什麼時候被調用不肯定,不要認爲必定能夠執行。

3  執行finalize方法時,可讓該對象轉又化爲可達狀態。

4  當執行finalize方法時,出線異常,不會報告異常,繼續執行。

 

public class FinalizeTest {
 @Override
 protected void finalize() throws Throwable {
  
  super.finalize();
     System.out.println("finalize");
  ft=this;
  
 }

    public void print(){
     System.out.println("print");
    }

 static FinalizeTest  ft=null;
 
 
 
 /**
  * @param args
  * @throws InterruptedException 
  */
 public static void main(String[] args) throws InterruptedException {
    new FinalizeTest();
     System.gc();

   //Thread.sleep(2000);   1

  //System.runFinalization();  2
          ft.print();
 }

}

 

這樣會有空指針異常

1   去掉1的註釋,註釋2不去掉,就不會有異常,是由於垃圾回收機制調用了finalize方法,使得ft引用指向了該對象,該線程睡2秒鐘就是爲了等待垃圾回收機制回收該對象,調用finalize方法,

在該方法ft引用到對象,不會有空指針異常。

2   去掉2的註釋,註釋1不去掉,也不會有異常,由於強制垃圾回收機制調用可恢復對象的finalize方法

 

 

對象有四種引用

強引用

建立一個對象,把這個對象賦予引用變量,就是強引用,若是一個對象具備強引用,那就 相似於必不可少的生活用品,垃圾回收器毫不會回收它。當內存空 間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足問題。

 

軟引用SoftReference

若是一個對象只具備軟引用,那就相似於無關緊要的生活用品。若是內存空間足夠,垃圾回收器就不會回收它,若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使用。軟引用可用來實現內存敏感的高速緩存。
軟引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。

 

弱引用WeakReference

若是一個對象只具備弱引用,那就相似於無關緊要的生活用品。 弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它 所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程, 所以不必定會很快發現那些只具備弱引用的對象。
弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

 

需引用PhantomReference

"虛引用"顧名思義,就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。
虛引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃 圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。程序能夠經過判斷引用隊列中是 否已經加入了虛引用,來了解

被引用的對象是否將要被垃圾回收。程序若是發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起必要的行動。

 

 建立一個強引用

  String str  =new String ("hello");

建立一個引用隊列

  ReferenceQueue  rq=new ReferenceQueue();

建立一個弱引用,並關聯引用隊列

   WeakReference  wr=new WeakReference(str,rq);

關係圖以下:

 

 String str=new String("hello");
  ReferenceQueue  rq=new ReferenceQueue();
  WeakReference  wr=new WeakReference(str,rq);
  
  System.out.println(wr.get());
  System.out.println(rq.poll()==wr);
  str=null;
  System.gc();
  System.runFinalization();
  System.out.println(wr.get());
  System.out.println(rq.poll()==wr);

 

輸出

hello
false
null
true

 

垃圾回收的時候,弱引用會加入到關聯的隊列中,因此最後輸出true。

 

如下爲摘抄的一段軟引用的例子  來自於(http://blog.csdn.net/arui319/article/details/8489451)

假設咱們的應用會用到大量的默認圖片,好比應用中有默認的頭像,默認遊戲圖標等等,這些圖片不少地方會用到。若是每次都去讀取圖片,因爲讀取文件須要硬件操做,速度較慢,會致使性能較低。因此咱們考慮將圖片緩存起來,須要的時候直接從內存中讀取。可是,因爲圖片佔用內存空間比較大,緩存不少圖片須要不少的內存,就可能比較容易發生OutOfMemory異常。這時,咱們能夠考慮使用軟引用技術來避免這個問題發生。

首先定義一個HashMap,保存軟引用對象。

 

private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();

 

 

再來定義一個方法,保存Bitmap的軟引用到HashMap。

 

    public void addBitmapToCache(String path) {

        // 強引用的Bitmap對象

        Bitmap bitmap = BitmapFactory.decodeFile(path);

        // 軟引用的Bitmap對象

        SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);

        // 添加該對象到Map中使其緩存

        imageCache.put(path, softBitmap);

    }

 

 

 

    獲取的時候,能夠經過SoftReference的get()方法獲得Bitmap對象。

 

    public Bitmap getBitmapByPath(String path) {

        // 從緩存中取軟引用的Bitmap對象

        SoftReference<Bitmap> softBitmap = imageCache.get(path);

        // 判斷是否存在軟引用

        if (softBitmap == null) {

            return null;

        }

        // 取出Bitmap對象,若是因爲內存不足Bitmap被回收,將取得空

        Bitmap bitmap = softBitmap.get();

        return bitmap;

    }

 

 

使用軟引用之後,在OutOfMemory異常發生以前,這些緩存的圖片資源的內存空間能夠被釋放掉的,從而避免內存達到上限,避免Crash發生。

須要注意的是,在垃圾回收器對這個Java對象回收前,SoftReference類所提供的get方法會返回Java對象的強引用,一旦垃圾線程回收該Java對象以後,get方法將返回null。因此在獲取軟引用對象的代碼中,必定要判斷是否爲null,以避免出現NullPointerException異常致使應用崩潰。

相關文章
相關標籤/搜索