java中的4种reference的差别和使用场景(含理论、代码和执行结果)
轉:https://blog.csdn.net/aitangyong/article/details/39453365
我們知道java語言提供了4種引用類型:強引用、軟引用(SoftReference)、弱引用(WeakReference)和幽靈引用(PhantomReference),與引用密切相關的,還有一個引用隊列ReferenceQueue。引用和引用隊列的關系,對于垃圾回收來說非常重要,學習垃圾回收機制,必須要先了解引用和引用隊列的使用方法。本文主要參考網上的一些理論,同時配合自己的一些測試代碼,更好的理解這些概念。這篇博客也解決了?System.gc()和-XX:+DisableExplicitGC啟動參數,以及DirectByteBuffer的內存釋放??中遺留的幽靈引用的問題。
1、強引用
? ? ?強引用不會被GC回收,并且在java.lang.ref里也沒有實際的對應類型,平時工作接觸的最多的就是強引用。
Object obj = new Object();這里的obj引用便是一個強引用。如果一個對象具有強引用,那就類似于必不可少的生活用品,垃圾回收器絕不會回收它。當內存空 間不足,Java虛擬機寧愿拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足問題。
2、軟引用
如果一個對象只具有軟引用,那就類似于可有可物的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只 要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。 軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
?
這里有幾點需要說明:
1、System.gc()告訴JVM這是一個執行GC的好時機,但具體執不執行由JVM決定(事實上這段代碼一般都會執行GC)
2、Thread.sleep(200); 這是因為從對象被回收到JVM將引用加入refQueue隊列,需要一定的時間。而且poll并不是一個阻塞方法,如果沒有數據會返回null,所以我們選擇等待一段時間。
3、弱引用
如果一個對象只具有弱引用,那就類似于可有可物的生活用品。弱引用與軟引用的區別在于:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由于垃圾回收器是一個優先級很低的線程, 因此不一定會很快發現那些只具有弱引用的對象。 ?弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回 收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。?
/**
* 弱引用: 當發生GC的時候,Weak引用對象總是會內回收回收。因此Weak引用對象會更容易、更快被GC回收。
* Weak引用對象常常用于Map數據結構中,引用占用內存空間較大的對象
*
* <pre>
* 如果不發生垃圾回收:
* java.lang.Object@f9f9d8
* null
* java.lang.Object@f9f9d8
* null
*
* 如果發生垃圾回收:
* java.lang.Object@f9f9d8
* null
* null
* java.lang.ref.WeakReference@422ede
*
* <pre>
*/
public static void weak() throws Exception
{
Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);
System.out.println(weakRef.get()); // java.lang.Object@f9f9d8
System.out.println(refQueue.poll());// null
?
// 清除強引用,觸發GC
obj = null;
System.gc();
?
System.out.println(weakRef.get());
?
// 這里特別注意:poll是非阻塞的,remove是阻塞的.
// JVM將弱引用放入引用隊列需要一定的時間,所以這里先睡眠一會兒
// System.out.println(refQueue.poll());// 這里有可能是null
?
Thread.sleep(200);
System.out.println(refQueue.poll());
// System.out.println(refQueue.poll());//這里一定是null,因為已經從隊列中移除
?
// System.out.println(refQueue.remove());
}
這里需要注意下:
1、remove這是一個阻塞方法,類似于J.U.C并發包下的阻塞隊列,如果沒有隊列沒有數據,那么當前線程一直等待。
2、如果隊列有數據,那么remove和pool都會將第一個元素出隊。
4、幽靈引用(虛引用)
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在于:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器回收一個對象時,如果發現它還有虛引用,就會把這個虛引用加入到與之關聯的引用隊列中。程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那么就可以在所引用的對象的內存被回收之前采取必要的行動。由于Object.finalize()方法的不安全性、低效性,常常使用虛引用完成對象回收前的資源釋放工作。參考我的另一篇博客:解釋為什么finalize是不安全的,不建議使用
?/**
* 當GC一但發現了虛引用對象,將會將PhantomReference對象插入ReferenceQueue隊列.
* 而此時PhantomReference所指向的對象并沒有被GC回收,而是要等到ReferenceQueue被你真正的處理后才會被回收.
*
* <pre>
* 不發生GC執行結果是:
* null
* null
* null
* null
*
* 發生GC執行結果是:
* null
* null
* null
* java.lang.ref.PhantomReference@87816d
* </pre>
*
* 虛引用在實現一個對象被回收之前必須做清理操作是很有用的,比finalize()方法更靈活
*/
public static void phantom() throws Exception
{
Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
PhantomReference<Object> phantom = new PhantomReference<Object>(obj,
refQueue);
System.out.println(phantom.get()); // java.lang.Object@f9f9d8
System.out.println(refQueue.poll());// null
?
obj = null;
System.gc();
?
// 調用phanRef.get()不管在什么情況下會一直返回null
System.out.println(phantom.get());
?
// 當GC發現了虛引用,GC會將phanRef插入進我們之前創建時傳入的refQueue隊列
// 注意,此時phanRef所引用的obj對象,并沒有被GC回收,在我們顯式地調用refQueue.poll返回phanRef之后
// 當GC第二次發現虛引用,而此時JVM將phanRef插入到refQueue會插入失敗,此時GC才會對obj進行回收
Thread.sleep(200);
System.out.println(refQueue.poll());
}
這里特別需要注意:當JVM將虛引用插入到引用隊列的時候,虛引用執行的對象內存還是存在的。但是PhantomReference并沒有暴露API返回對象。如NIO直接內存的自動回收,就使用到了sun.misc.Cleaner
?
public class Cleaner extends PhantomReference
{
}
JDK底層源碼查詢網站:http://www.docjar.com/html/api/sun/misc/Cleaner.java.html
5、小結
引用和引用隊列提供了一種通知機制,允許我們知道對象已經被銷毀或者即將被銷毀。GC要回收一個對象的時候,如果發現該對象有軟、弱、虛引用的時候,會將這些引用加入到注冊的引用隊列中。軟引用和弱引用差別不大,JVM都是先把SoftReference和WeakReference中的referent字段值設置成null,之后加入到引用隊列;而虛引用則不同,如果某個堆中的對象,只有虛引用,那么JVM會將PhantomReference加入到引用隊列中,JVM不會自動將referent字段值設置成null。
參考資料:
Java:對象的強、軟、弱和虛引用 ? ?http://zhangjunhd.blog.51cto.com/113473/53092/
Java 中的 Reference ? ? ? ? ? ? ?http://www.cnblogs.com/newcj/archive/2011/05/15/2046882.html
總結
以上是生活随笔為你收集整理的java中的4种reference的差别和使用场景(含理论、代码和执行结果)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 图表 word_java Fr
- 下一篇: str045漏洞提权linux,Linu