天天看點

JAVA中的強引用,弱引用,虛引用和軟引用

筆者在編寫Android程式時,經常會使用到異步加載圖檔的機制,在這個功能中,筆者會使用到SoftReference類,也就是JAVA的軟引用,另外強引用就更不用說了,用的頻率更高,是以筆者結合自己的經驗和查閱的資料,将JAVA中這幾個不同的引用方式整理了一下,分享給閱讀的同行!

在JAVA中有四種不同的引用方式

1.強引用

2.弱引用

3.虛引用

4.軟引用

1.強引用

我們平常用的最多的就是強引用了,如:String s = new String("opps"),這種形式的引用稱為強引用。

強引用有以下幾個特點:

1)強引用可以直接通路目标對象 ;

2)強引用所指向的對象在任何時候都不會被系統回收 ;

3)由于2的原因,強引用可能導緻記憶體洩漏。

package com.kameleon.test;

public class StrongReference {
	public static void main(String[] args){
		String str = new String("opps");
		System.gc();
		System.runFinalization();
		System.out.println(str);
	}
}
           

這個是輸出:

JAVA中的強引用,弱引用,虛引用和軟引用

我們可以看到,垃圾回收後,依然可以列印出str所指向的opps,是以強引用所指向的對象不會被垃圾回收器回收。這樣就可能會導緻記憶體洩露。強引用指向的對象,垃圾回收器是不會自動幫你回收對象所占的記憶體,一旦對象被強引用,那麼強引用本身就強迫這個對象保留在記憶體中,是以需要你自己手動去釋放不需要再次别使用的對象所占的空間,這樣你可能就要多次重複相同的釋放記憶體的動作了,因為此時記憶體回收器不會回收強引用指向的記憶體空間

2.弱引用

弱引用通過weakReference類來實作的。弱引用與軟引用的差別在于:隻具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的記憶體區域的過程中,一旦發現了隻具有弱引用的對象,不管目前記憶體空間足夠與否,都會回收它的記憶體。不過,由于垃圾回收器是一個優先級很低的線程,是以不一定會很快發現那些隻具有弱引用的對象。弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛拟機就會把這個弱引用加入到與之關聯的引用隊列中。

我們來測試一下:

package com.kameleon.test;

import java.lang.ref.WeakReference;

public class WeakReferenceTest {
    public static void main(String[] args) {
    	String str = new String("opps");
    	//建立一個軟引用對象 指向str對象
    	WeakReference<String> wr = new WeakReference<String> (str);
    	str =null;
    	//輸出
    	System.out.println(wr.get());//opps
    	//強制垃圾回收
    	System.gc();
    	System.out.println(wr.get());//null
    }
}
           

這是輸出:

JAVA中的強引用,弱引用,虛引用和軟引用

3.虛引用

“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個差別在于:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的記憶體之前,把這個虛引用加入到與之關聯的引用隊列中。程式可以通過檢測與虛引用關聯的虛引用隊列是否已經包含了指定的虛引用,進而了解虛引用的對象是否即将被回收。

我們來測試下:

package com.kameleon.test;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceTest {
	public static void main(String[] args){
		// 建立一個對象
		String str = new String("opps");
		//  建立一個引用隊列
		ReferenceQueue<String> rq = new ReferenceQueue<String>();
		//建立一個虛引用,指定引用對象.不能單獨使用必須關聯引用隊列
		PhantomReference pr = new PhantomReference(str,rq);
		//切斷強引用
		str = null;
		//試圖取得虛引用對象
		System.out.println(pr.get());
		//垃圾回收
		System.gc();
		System.runFinalization();
		//取出引隊列中的最先進入隊列的引用與pr進行比較
		System.out.println(rq.poll()==pr);  
	}
}
           

這個是輸出:

JAVA中的強引用,弱引用,虛引用和軟引用

4.軟引用

如果一個對象隻具有軟引用,則記憶體空間足夠,垃圾回收器就不會回收它;如果記憶體空間不足了,就會回收這些對象的記憶體。隻要垃圾回收器沒有回收它,該對象就可以被程式使用。我們可以嘗試使用這樣的指令:

java -Xmx1m -Xms1m SoftReferenceTest(這是你建立的類名)指令,強制堆記憶體為1M時,當你建立大量軟引用對象時,如果他們的總共的大小超過了1M,軟引用引用對象将被回收。軟引用可用來實作記憶體敏感的高速緩存。

簡單總結一下:

如果使用軟引用,弱引用,虛引用的引用方式引用對象,垃圾回收就能夠随意的釋放這些對象,如果希望盡可能減小程式在其聲明周期中所占用的記憶體大小,可以靈活使用這些引用。如果使用了這些引用就不能保留這些對象的強引用(強引用應該置null),否則就浪費了這些類提供的任何好處。

如果有問題,歡迎大家提出來!