Java 中 Reference用法詳解
Java Reference詳解
在 jdk 1.2 及其以后,引入了強引用、軟引用、弱引用、虛引用這四個概念。網(wǎng)上很多關(guān)于這四個概念的解釋,但大多是概念性的泛泛而談,今天我結(jié)合著代碼分析了一下,首先我們先來看定義與大概解釋(引用類型在包 Java.lang.ref 里)。
1、強引用(StrongReference)
強引用不會被GC回收,并且在java.lang.ref里也沒有實際的對應(yīng)類型。舉個例子來說:
Object obj = new Object();
這里的obj引用便是一個強引用,不會被GC回收。
2、軟引用(SoftReference)
軟引用在JVM報告內(nèi)存不足的時候才會被GC回收,否則不會回收,正是由于這種特性軟引用在caching和pooling中用處廣泛。軟引用的用法:
Object obj = new Object(); SoftReference<Object> softRef = new SoftReference(obj); // 使用 softRef.get() 獲取軟引用所引用的對象 Object objg = softRef.get();
3、弱引用(WeakReference)
當(dāng)GC一但發(fā)現(xiàn)了弱引用對象,將會釋放WeakReference所引用的對象。弱引用使用方法與軟引用類似,但回收策略不同。
4、虛引用(PhantomReference)
當(dāng)GC一但發(fā)現(xiàn)了虛引用對象,將會將PhantomReference對象插入ReferenceQueue隊列,而此時PhantomReference所指向的對象并沒有被GC回收,而是要等到ReferenceQueue被你真正的處理后才會被回收。虛引用的用法:
Object obj = new Object(); ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue); // 調(diào)用phanRef.get()不管在什么情況下會一直返回null Object objg = phanRef.get(); // 如果obj被置為null,當(dāng)GC發(fā)現(xiàn)了虛引用,GC會將phanRef插入進(jìn)我們之前創(chuàng)建時傳入的refQueue隊列 // 注意,此時phanRef所引用的obj對象,并沒有被GC回收,在我們顯式地調(diào)用refQueue.poll返回phanRef之后 // 當(dāng)GC第二次發(fā)現(xiàn)虛引用,而此時JVM將phanRef插入到refQueue會插入失敗,此時GC才會對obj進(jìn)行回收 Reference<? extends Object> phanRefP = refQueue.poll();
看了簡單的定義之后,我們結(jié)合著代碼來測試一下,強引用就不用說了,軟引用的描述也很清楚,關(guān)鍵是 “弱引用” 與 “虛引用”。
弱引用:
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這是一個執(zhí)行GC的好時機,但具體執(zhí)不執(zhí)行由JVM決定,因此當(dāng)JVM決定執(zhí)行GC,得到的結(jié)果便是(事實上這段代碼一般都會執(zhí)行GC):
java.lang.Object@de6ced null null java.lang.ref.WeakReference@1fb8ee3
從執(zhí)行結(jié)果得知,通過調(diào)用weakRef.get()我們得到了obj對象,由于沒有執(zhí)行GC,因此refQueue.poll()返回的null,當(dāng)我們把obj = null;此時沒有引用指向堆中的obj對象了,這里JVM執(zhí)行了一次GC,我們通過weakRef.get()發(fā)現(xiàn)返回了null,而refQueue.poll()返回了WeakReference對象,因此JVM在對obj進(jìn)行了回收之后,才將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()); }
同樣,當(dāng)JVM執(zhí)行了GC,得到的結(jié)果便是:
null null null java.lang.ref.PhantomReference@1fb8ee3
從執(zhí)行結(jié)果得知,我們先前說的沒有錯,phanRef.get()不管在什么情況下,都會返回null,而當(dāng)JVM執(zhí)行GC發(fā)現(xiàn)虛引用之后,JVM并沒有回收obj,而是將PhantomReference對象插入到對應(yīng)的虛引用隊列refQueue中,當(dāng)調(diào)用refQueue.poll()返回PhantomReference對象時,poll方法會先把PhantomReference的持有隊列queue(ReferenceQueue<? super T>)置為NULL,NULL對象繼承自ReferenceQueue,將enqueue(Reference paramReference)方法覆蓋為return false,而此時obj再次被GC發(fā)現(xiàn)時,JVM再將PhantomReference插入到NULL隊列中便會插入失敗返回false,此時GC便會回收obj。事實上通過這段代碼我們也的卻看不出來obj是否被回收,但通過 PhantomReference 的javadoc注釋中有一句是這樣寫的:
Once the garbage collector decides that an object obj is phantom-reachable, it is being enqueued on the corresponding queue, but its referent is not cleared. That is, the reference queue of the phantom reference must explicitly be processed by some application code.
翻譯一下(這句話很簡單,我相信很多人應(yīng)該也看得懂):
一旦GC決定一個“obj”是虛可達(dá)的,它(指PhantomReference)將會被入隊到對應(yīng)的隊列,但是它的指代并沒有被清除。也就是說,虛引用的引用隊列一定要明確地被一些應(yīng)用程序代碼所處理。
弱引用與虛引用的用處
軟引用很明顯可以用來制作caching和pooling,而弱引用與虛引用呢?其實用處也很大,首先我們來看看弱引用,舉個例子:
class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( object ); } }
所有我添加進(jìn) registeredObjects 中的object永遠(yuǎn)不會被GC回收,因為這里有個強引用保存在registeredObjects里,另一方面如果我把代碼改為如下:
class Registry { private Set registeredObjects = new HashSet(); public void register(Object object) { registeredObjects.add( new WeakReference(object) ); } }
現(xiàn)在如果GC想要回收registeredObjects中的object,便能夠?qū)崿F(xiàn)了,同樣在使用HashMap如果想實現(xiàn)如上的效果,一種更好的實現(xiàn)是使用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.
翻譯一下:
虛引用在實現(xiàn)一個對象被回收之前必須做清理操作是很有用的。有時候,他們比finalize()方法更靈活。
很明顯的,虛引用可以用來做對象被回收之前的清理工作。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Selenium Webdriver實現(xiàn)截圖功能的示例
今天小編就為大家分享一篇Selenium Webdriver實現(xiàn)截圖功能的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05Springmvc項目web.xml中servlet-mapping路徑映射配置注意說明
這篇文章主要介紹了Springmvc項目web.xml中servlet-mapping路徑映射配置注意說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12Spring data jpa @Query update的坑及解決
這篇文章主要介紹了Spring data jpa @Query update的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02SpringCloud使用Feign實現(xiàn)動態(tài)路由操作
這篇文章主要介紹了SpringCloud使用Feign實現(xiàn)動態(tài)路由操作,文章圍繞主題展開詳細(xì)的內(nèi)容介紹具有一定的參考價值,需要的小伙伴可以參考一下2022-06-06