這篇文章主要介紹了Java 中Reference用法詳解的相關資料,需要的朋友可以參考下
Java Reference詳解
在jdk 1.2 及其以後,引入了強引用、軟引用、弱引用、虛引用這四個概念。網路上很多關於這四個概念的解釋,但大多是概念性的泛泛而談,今天我結合著程式碼分析了一下,首先我們先來看定義與大概解釋(引用型別在套件Java.lang.ref 裡)。
1、強引用(StrongReference)
強引用不會被GC回收,並且在java.lang.ref裡也沒有實際的對應類型。舉個例子來說:
Object obj = new Object();
這裡的obj引用便是一個強引用,不會被GC回收。
2、軟引用(SoftReference)
軟引用在JVM報告記憶體不足的時候才會被GC回收,否則不會回收,正是由於這種特性軟引用在caching和pooling中用處廣泛。軟引用的用法:
Object obj = new Object(); SoftReference<Object> softRef = new SoftReference(obj); // 使用 softRef.get() 获取软引用所引用的对象 Object objg = softRef.get();
3、弱引用(WeakReference)
當GC一但發現了弱引用對象,將會釋放WeakReference所引用的物件。弱引用使用方法與軟引用類似,但回收策略不同。
4、虛引用(PhantomReference)
當GC一但發現了虛引用對象,將會將PhantomReference對象插入ReferenceQueue隊列,而此時PhantomReference所指向的物件並沒有被GC回收,而是要等到ReferenceQueue被你真正的處理後才會被回收。虛引用的用法:
Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue); // 调用phanRef.get()不管在什么情况下会一直返回null Object objg = phanRef.get(); // 如果obj被置为null,当GC发现了虚引用,GC会将phanRef插入进我们之前创建时传入的refQueue队列 // 注意,此时phanRef所引用的obj对象,并没有被GC回收,在我们显式地调用refQueue.poll返回phanRef之后 // 当GC第二次发现虚引用,而此时JVM将phanRef插入到refQueue会插入失败,此时GC才会对obj进行回收 Reference<? extends Object> phanRefP = refQueue.poll();
看了簡單的定義之後,我們結合著程式碼來測試一下,強引用就不用說了,軟引用的描述也很清楚,關鍵是「弱引用」 與「虛引用」。
弱引用:
public static void main(String[] args) throws InterruptedException { Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue); System.out.println(weakRef.get()); System.out.println(refQueue.poll()); obj = null; System.gc(); System.out.println(weakRef.get()); System.out.println(refQueue.poll()); }
#由於System.gc()告訴JVM這是執行GC的好時機,但具體執不執行由JVM決定,因此當JVM決定執行GC,得到的結果就是(事實上這段程式碼一般都會執行GC):
java.lang.Object@de6ced null null java.lang.ref.WeakReference@1fb8ee3
從執行結果得知,透過呼叫weakRef.get()我們得到了obj對象,由於沒有執行GC,因此refQueue.poll()返回的null,當我們把obj = null;此時沒有引用指向堆中的obj對象了,這裡JVM執行了一次GC,我們透過weakRef.get()發現返回了null,而refQueue.poll()返回了WeakReference對象,因此JVM在對obj進行了回收之後,才將weakRef插入到refQueue隊列中。
虛引用:
public static void main(String[] args) throws InterruptedException { Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue); System.out.println(phanRef.get()); System.out.println(refQueue.poll()); obj = null; System.gc(); System.out.println(phanRef.get()); System.out.println(refQueue.poll()); }
同樣,當JVM執行了GC,得到的結果就是:
null null null java.lang.ref.PhantomReference@1fb8ee3
從執行結果得知,我們先前說的沒有錯,phanRef.get()不管在什麼情況下,都會返回null,而當JVM執行GC發現虛引用之後,JVM並沒有回收obj,而是將PhantomReference物件插入對應的虛引用佇列refQueue中,當呼叫refQueue.poll()傳回PhantomReference物件時,poll方法會先把PhantomReference的持有佇列queue(ReferenceQueue super T>)置為NULL,NULL物件繼承自ReferenceQueue,將enqueue(Reference paramReference)方法覆寫為return false,而此時obj再次被GC發現時,JVM再將PhantomReference插入到NULL佇列中便會插入失敗回傳false,此時GC便會回收obj。事實上透過這段程式碼我們也的卻看不出來obj是否被回收,但透過PhantomReference 的javadoc註解中有一句是這樣寫的:
Once the garbage collector decides that an object obj is phantom-reach#able, it is being enqueued on the corresponding queue, but its referent is not cleared. That is, the reference queue of the reference the reference the phantom reference must explicitly be processed by some application code.
##翻譯一下(這句話很簡單,我相信很多人應該也看得懂):一旦GC決定一個「obj」是虛可達的,它(指PhantomReference)將會被入隊到對應的隊列,但是它的指代並沒有被清除。也就是說,虛引用的引用隊列一定要明確地被一些應用程式程式碼所處理。弱引用與虛引用的用處#
软引用很明显可以用来制作caching和pooling,而弱引用与虚引用呢?其实用处也很大,首先我们来看看弱引用,举个例子:
class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( object ); } }
所有我添加进 registeredObjects 中的object永远不会被GC回收,因为这里有个强引用保存在registeredObjects里,另一方面如果我把代码改为如下:
class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( new WeakReference(object) ); } }
现在如果GC想要回收registeredObjects中的object,便能够实现了,同样在使用HashMap如果想实现如上的效果,一种更好的实现是使用WeakHashMap。
而虚引用呢?我们先来看看javadoc的部分说明:
Phantom references are useful for implementing cleanup operations that are necessary before an object gets garbage-collected. They are sometimes more flexible than the finalize() method.
翻译一下:
虚引用在实现一个对象被回收之前必须做清理操作是很有用的。有时候,他们比finalize()方法更灵活。
很明显的,虚引用可以用来做对象被回收之前的清理工作。
以上是Java中Reference用法介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!