1. 程式人生 > >JAVA基礎:強引用、軟引用、弱引用、虛引用

JAVA基礎:強引用、軟引用、弱引用、虛引用

生活

任何傻瓜都能寫出計算機可以理解的程式碼。好的程式設計師能寫出人能讀懂的程式碼。

前言

在JAVA中,開發人員不需要像C開發人員那樣手動去管理記憶體中物件的生命週期,但是如果需要某些物件具備一定的生命週期(當記憶體不足的時候可以回收一些沒有必要的物件,從而規避一些OOM的風險),此時可以通過弱引用和軟引用、虛引用來實現生命週期的管理。

強引用

注意:JAVA中寫的大部分程式碼都是強引用。
當一個物件被一個強引用關聯時,JVM必定不會回收這個物件,就算記憶體不足了,寧可出現OOM也不回收。
例如這段程式碼:

public static void  test() {
		Object[] object = new Object[10000];
	}

在分配記憶體給陣列時,即使出現記憶體不足,也不會回收。
注意在這個方法執行完畢後,object這個強引用也就不存在了,那陣列物件就能被jvm回收了。

軟引用

軟引用用來描述一些有用但又沒那麼必須的物件,,在Java中用java.lang.ref.SoftReference類來表示。被軟引用關聯的物件在記憶體不足時就會被JVM回收,這一點可以很好的用在oom的場景上,並且這個特性適合用在快取上:比如網頁快取、圖片快取。
軟引用可以與一個引用佇列關聯使用,當一個軟引用所引用的物件被JVM回收,這個軟引用就會被加入到與之關聯的引用佇列上。
程式碼如下:

SoftReference<String> s = new SoftReference<String>(new String("a"));
		System.out.println(s.get());

弱引用

弱引用用來描述一些非必須物件,它的優先順序比軟引用還要低,在JAVA中用java.lang.ref.WeakRefrence來表示。
被弱引用關聯的物件,在JVM進行垃圾回收時,無論記憶體是否充足,都會回收。
同樣,弱引用也可以與一個引用佇列關聯使用,當一個弱引用所描述的物件被JVM回收,這個弱引用就會被加入與之關聯的引用佇列上。

ReferenceQueue<String> q = new ReferenceQueue<>();
		WeakReference<String> s = new WeakReference<String>(new String("a"),q);
		
		System.out.println(s.get());
		System.out.println(q.poll());
		System.gc();
		System.out.println(s.get());
		System.out.println(q.poll());

結果:
a
null
null
[email protected]

虛引用

虛引用跟前面的弱引用、軟引用不一樣,它不影響物件的生命週期,被他所表示的物件可以隨時被垃圾回收器回收。
在java中用java.lang.ref.PhantomReference類表示一個虛引用。
虛引用必須與引用佇列關聯使用,當JVM準備回收一個物件時,如果發現它存在虛引用,會先把它放到它關聯的引用佇列,程式可以通過引用佇列裡是否有相關的虛引用,來判斷物件是否即將被回收。
如果發現某個虛引用出現在引用佇列裡,既可以在這個引用所引用的物件的記憶體空間被回收之前做出一些必要的操作。

 ReferenceQueue<String> queue = new ReferenceQueue<String>();
	        PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
	        System.out.println(pr.get());

null
注意虛引用的GET取到的物件只有null。

虛引用的一個使用:DirectByteBuffer

如何利用軟引用和弱引用解決OOM問題

前面講了關於軟引用和弱引用相關的基礎知識,那麼到底如何利用它們來優化程式效能,從而避免OOM的問題呢?

下面舉個例子,假如有一個應用需要讀取大量的本地圖片,如果每次讀取圖片都從硬碟讀取,則會嚴重影響效能,但是如果全部載入到記憶體當中,又有可能造成記憶體溢位,此時使用軟引用可以解決這個問題。

設計思路是:用一個HashMap來儲存圖片的路徑 和 相應圖片物件關聯的軟引用之間的對映關係,在記憶體不足時,JVM會自動回收這些快取圖片物件所佔用的空間,從而有效地避免了OOM的問題。在Android開發中對於大量圖片下載會經常用到。