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