Java中引用的詳解


Java中沒有指針,到處都是引用(除了基本類型)。所以,當然,你肯定知道java的引用,並用了很久,但是是不是對此了解地比較全面?而這些引用有什么作用,且有什么不同呢?
Java中有個java.lang.ref包,這里面都是描述引用對象的,包括了Reference,SoftReference,WeakReference和PhantomReference。其中,Reference是基類其他三個類的基類。下面就這幾種引用對象做個說明。

強引用(Strong References)
我們每天都在用強引用(如果你每天都在用java的話),一段如下的代碼:
HashMap mapRef = new HashMap();
就是通過new HashMap();創建了一個對象(這東西在heap上),並把一個強引用存到了
 mapRef引用中。而強引用之為“強”的地方就在於其對垃圾回收器所產生的影響。如果一個對象可以經由一條強引用鏈可達(也就說這個對象是Strongly reachable),那么就說明這個類不適合被垃圾回收。我們也絕對不希望正在使用的對象一下子了無蹤跡了。

但是強引用會對我們的應用產生很“強”的影響。比如:經常會碰到一個問題,緩存。通過Set(以set為例吧)模擬的緩存,在應用運行的過程中,會不斷有 大量對象添加到set中。這些對象並不會被GC回收,並且隨着對象的增多,我們的內存也會不斷變大,終於有一天OutOfMemory啦。其實,set可 能使用頻率還不大,HashMap的key-value模式讓我們愛不釋手,引誘着你去不斷地put,put,撲通。。
OutOfMemory啦。
對於java這門有魅力,有活力,有朝氣,有老氣,有垃圾自動回收機制的語言而言,我們不應被上述問題所困擾。

弱引用(Weak Reference)
弱引用,就是不是那種用強制的方式要求對象存在於內存的引用。可以借助垃圾回收器來判斷某個對象的可達性,並幫你回收弱引用所引用的對象。如何創建一個弱引用呢:
StringBuffer sbuff = new StringBuffer("What is a WeakReference?");
WeakReference<StringBuffer> wref = new WeakReference
<StringBuffer>(sbuff);

sbbuff=null;//這里的操作,看情況定。在這里主要為了說明,原來強引用的一個對象,被轉成一個弱引用來指向。
然后通過wref.get()來獲取sbuff對象。因為弱引用並沒強悍到可以阻止垃圾回收器回收wref引用的對象(這里要區分引用對象和被引用的對象,在創建一個
 WeakReference時,就有一個引用對象誕生了,它指向了一個被引用的對象),所以可能從某一刻開始,wref.get()就開始給我們null了。
對於上面提到的使用HashMap時,對象過多(並且不刪除,而被垃圾回收)會造成的OutOfMemory問題,可以通過WeakHashMap來實現,這樣垃圾回收器就會幫我們處理那些時間長了不用,還占地方的類了,而不至於出現
OutOfMemory問題

引用隊列(
 ReferenceQueue,何方神聖?)
WeakReference開始返回null時,說明它原來指向的對象已經變成了垃圾。另外也說明這個WeakReference對我們已經沒多少用處了。我們需要做點什么來處理這些沒用的東西?
逢此危難之際,
ReferenceQueue閃亮登場。據官方資料,其定義為:
Reference queues, to which registered reference objects are appended by the garbage collector after the appropriate reachability changes are detected. 
(當檢測到相應的可達性發生改變后,
垃圾回收器就會將注冊有此隊列的引用對象添加到這個引用隊列中。
如何注冊一個隊列?在
WeakReference的構造函數中,有一個WeakReference(T referent, ReferenceQueue<? super T> q)。所以,當一個WeakReference變成一個死引用時,它就會被添加到這個ReferenceQueue中,只要定期的來處理一下這個ReferenceQueue就可以了。

不同的引用

引用實際上是有好幾種的,就如我們在java.lang.ref包中看到的那樣,再加上強引用,有4種引用類型:強(Strong)、軟(Soft)、弱(Weak)、幻象(Phantom),引用依次從強到弱。接下來,就看看其他的引用。

軟引用(Soft Reference)

軟引用,跟弱引用功能挺像的。但是軟引用指向的對象一般會比弱引用的存活時間長一些,直到內存空間不夠時,才會被垃圾回收。一個Weakly reachable對象,是僅僅被WeakReference引用的,並且會被垃圾回收器在下一個垃圾回收周期中丟棄;而一個Softly reachable對象,則會活地時間長一些。

軟引用給我們帶來了很大的實惠,尤其是緩存的實現。比如,我們有一個緩存池,對於內存比較緊張的情況來說,一旦要達到memory上限時,垃圾回收器就將Soft Reference引用的對象釋放掉,以避免OutOfMemory慘劇的發生。

幻象引用(Phantom Reference)

幻象引用,是不同於Soft和Weak的引用。幻象引用對指向對象的引用強度如此之脆弱,以至於調用方法get()時,總是返回null。它的主要作用就是跟蹤所指向的對象已經dead了,那么其跟WeakReference的區別是什么呢?

它們的區別就在於:是在什么時候,這個引用對象被添加到引用隊列中的。WeakReference是在當其所引用的對象變成Weakly Reachable時被添加到引用隊列中的,這發生在一個對象被finalization或被垃圾回收之前的。理論上講,一個對象在被finalize()時,是可以被“復活”的,但此時WeakReference已經沒活力了。對幻象引用來說,只有當其所引用的對象被徹底垃圾回收(從內存中消除)時,才會添加到引用隊列中。而幻象引用的get方法總是返回null,就是要避免我們來“復活”一個奄奄一息的對象。

那么幻象引用有何實際作用?

第一、我們可以在監控一個對象什么時候被徹底銷毀了。那樣,就可以做點什么其他事情(看你是不是有這方面的需求啦)。不過實際中,這種情況也不多的。

第二、因為理論上存在的,可以通過一個對象的finalize()方法“復活”一個對象,那么如果在一次垃圾回收處理時,調用了一個對象的finalize()(這個方法在何時調用不確定),卻讓它復活了。要再苦苦等待finalize()的執行,還不知道要到猴年馬月的(天下大赦可以有,但不是天天有。誰知道啥時候天朝更替,人主易位)。突然就出現了OutOfMemory錯誤了。

而幻象引用絕對不會再讓對象復活,只要被它逮着了,事情就簡單了:掛定了!

總而言之,言而總之,歸根結底:

引用是關系垃圾回收的。

轉載自:http://www.cnblogs.com/ericchen/


import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;


class VeryBig{
	private static final int SIZE = 10000;
	private long[] la = new long[SIZE];
	private String ident;
	public VeryBig(String id) {
		ident = id;
	}
	@Override
	public String toString() {
		return ident; 
	}
	protected void finalize() {
		System.out.println("finalize...." + ident);
	}
}

public class Test{
	private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();
	public static void checkQueue() {
		Reference<? extends VeryBig> inq = rq.poll();
		if (inq != null) {
			System.out.println("in Queue : " + inq.get());
		}
	}
	public static void main(String[] args) {
		int size = 10;
		System.out.println("--------Soft------------");
		LinkedList<SoftReference<VeryBig>> sa = new LinkedList<SoftReference<VeryBig>>();
		for (int i = 0; i < size; ++i) {
			sa.add(new SoftReference<VeryBig>(new VeryBig("soft" + i), rq));
			System.out.println("just created soft: " + sa.getLast().get());
			checkQueue();
		}
		SoftReference<VeryBig> s = new SoftReference<VeryBig>(new VeryBig("soft"));
		
		System.out.println("--------Weak------------");
		LinkedList<WeakReference<VeryBig>> wa = new LinkedList<WeakReference<VeryBig>>();
		for (int i = 0; i < size; ++i) {
			wa.add(new WeakReference<VeryBig>(new VeryBig("weak" + i), rq));
			System.out.println("just create weak : " + wa.getLast().get());
			checkQueue();
		}
		WeakReference<VeryBig> w = new WeakReference<VeryBig>(new VeryBig("Weak"));
		
		System.gc();
		
		
		
		
		LinkedList<PhantomReference<VeryBig>> pa = new LinkedList<PhantomReference<VeryBig>>();
		for (int i = 0; i < size; ++i) {
			pa.add(new PhantomReference<VeryBig>(new VeryBig("phantom " + i), rq));
			System.out.println("just create Phantom : " + pa.getLast().get());
			checkQueue();
		}
	}
}

輸出:
--------Soft------------
just created soft: soft0
just created soft: soft1
just created soft: soft2
just created soft: soft3
just created soft: soft4
just created soft: soft5
just created soft: soft6
just created soft: soft7
just created soft: soft8
just created soft: soft9
--------Weak------------
just create weak : weak0
just create weak : weak1
just create weak : weak2
just create weak : weak3
just create weak : weak4
just create weak : weak5
just create weak : weak6
just create weak : weak7
just create weak : weak8
just create weak : weak9
just create Phantom : null
just create Phantom : null
finalize....weak2
finalize....Weak
in Queue : null
finalize....weak9
just create Phantom : null
finalize....weak8
in Queue : null
finalize....weak7
just create Phantom : null
finalize....weak6
finalize....weak5
finalize....weak4
finalize....weak3
finalize....weak1
finalize....weak0
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null
just create Phantom : null
in Queue : null

  

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM