日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java中的4种reference的差别和使用场景(含理论、代码和执行结果)

發(fā)布時(shí)間:2023/12/10 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中的4种reference的差别和使用场景(含理论、代码和执行结果) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn):https://blog.csdn.net/aitangyong/article/details/39453365

我們知道java語(yǔ)言提供了4種引用類型:強(qiáng)引用、軟引用(SoftReference)、弱引用(WeakReference)和幽靈引用(PhantomReference),與引用密切相關(guān)的,還有一個(gè)引用隊(duì)列ReferenceQueue。引用和引用隊(duì)列的關(guān)系,對(duì)于垃圾回收來(lái)說(shuō)非常重要,學(xué)習(xí)垃圾回收機(jī)制,必須要先了解引用和引用隊(duì)列的使用方法。本文主要參考網(wǎng)上的一些理論,同時(shí)配合自己的一些測(cè)試代碼,更好的理解這些概念。這篇博客也解決了?System.gc()和-XX:+DisableExplicitGC啟動(dòng)參數(shù),以及DirectByteBuffer的內(nèi)存釋放??中遺留的幽靈引用的問(wèn)題。

1、強(qiáng)引用

? ? ?強(qiáng)引用不會(huì)被GC回收,并且在java.lang.ref里也沒(méi)有實(shí)際的對(duì)應(yīng)類型,平時(shí)工作接觸的最多的就是強(qiáng)引用。
  Object obj = new Object();這里的obj引用便是一個(gè)強(qiáng)引用。如果一個(gè)對(duì)象具有強(qiáng)引用,那就類似于必不可少的生活用品,垃圾回收器絕不會(huì)回收它。當(dāng)內(nèi)存空 間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤,使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來(lái)解決內(nèi)存不足問(wèn)題。

2、軟引用

如果一個(gè)對(duì)象只具有軟引用,那就類似于可有可物的生活用品。如果內(nèi)存空間足夠,垃圾回收器就不會(huì)回收它,如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存。只 要垃圾回收器沒(méi)有回收它,該對(duì)象就可以被程序使用。軟引用可用來(lái)實(shí)現(xiàn)內(nèi)存敏感的高速緩存。 軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾回收,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。

?


這里有幾點(diǎn)需要說(shuō)明:

1、System.gc()告訴JVM這是一個(gè)執(zhí)行GC的好時(shí)機(jī),但具體執(zhí)不執(zhí)行由JVM決定(事實(shí)上這段代碼一般都會(huì)執(zhí)行GC)

2、Thread.sleep(200); 這是因?yàn)閺膶?duì)象被回收到JVM將引用加入refQueue隊(duì)列,需要一定的時(shí)間。而且poll并不是一個(gè)阻塞方法,如果沒(méi)有數(shù)據(jù)會(huì)返回null,所以我們選擇等待一段時(shí)間。

3、弱引用

如果一個(gè)對(duì)象只具有弱引用,那就類似于可有可物的生活用品。弱引用與軟引用的區(qū)別在于:只具有弱引用的對(duì)象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存。不過(guò),由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程, 因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象。 ?弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回 收,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。?

/**

* 弱引用: 當(dāng)發(fā)生GC的時(shí)候,Weak引用對(duì)象總是會(huì)內(nèi)回收回收。因此Weak引用對(duì)象會(huì)更容易、更快被GC回收。

* Weak引用對(duì)象常常用于Map數(shù)據(jù)結(jié)構(gòu)中,引用占用內(nèi)存空間較大的對(duì)象

*

* <pre>

* 如果不發(fā)生垃圾回收:

* java.lang.Object@f9f9d8

* null

* java.lang.Object@f9f9d8

* null

*

* 如果發(fā)生垃圾回收:

* 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

?

// 清除強(qiáng)引用,觸發(fā)GC

obj = null;

System.gc();

?

System.out.println(weakRef.get());

?

// 這里特別注意:poll是非阻塞的,remove是阻塞的.

// JVM將弱引用放入引用隊(duì)列需要一定的時(shí)間,所以這里先睡眠一會(huì)兒

// System.out.println(refQueue.poll());// 這里有可能是null

?

Thread.sleep(200);

System.out.println(refQueue.poll());

// System.out.println(refQueue.poll());//這里一定是null,因?yàn)橐呀?jīng)從隊(duì)列中移除

?

// System.out.println(refQueue.remove());

}

這里需要注意下:

1、remove這是一個(gè)阻塞方法,類似于J.U.C并發(fā)包下的阻塞隊(duì)列,如果沒(méi)有隊(duì)列沒(méi)有數(shù)據(jù),那么當(dāng)前線程一直等待。

2、如果隊(duì)列有數(shù)據(jù),那么remove和pool都會(huì)將第一個(gè)元素出隊(duì)。
4、幽靈引用(虛引用)

虛引用主要用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng)。虛引用與軟引用和弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。程序可以通過(guò)判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來(lái)了解被引用的對(duì)象是否將要被垃圾回收。如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)。由于Object.finalize()方法的不安全性、低效性,常常使用虛引用完成對(duì)象回收前的資源釋放工作。參考我的另一篇博客:解釋為什么finalize是不安全的,不建議使用

?/**

* 當(dāng)GC一但發(fā)現(xiàn)了虛引用對(duì)象,將會(huì)將PhantomReference對(duì)象插入ReferenceQueue隊(duì)列.

* 而此時(shí)PhantomReference所指向的對(duì)象并沒(méi)有被GC回收,而是要等到ReferenceQueue被你真正的處理后才會(huì)被回收.

*

* <pre>

* 不發(fā)生GC執(zhí)行結(jié)果是:

* null

* null

* null

* null

*

* 發(fā)生GC執(zhí)行結(jié)果是:

* null

* null

* null

* java.lang.ref.PhantomReference@87816d

* </pre>

*

* 虛引用在實(shí)現(xiàn)一個(gè)對(duì)象被回收之前必須做清理操作是很有用的,比f(wàn)inalize()方法更靈活

*/

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();

?

// 調(diào)用phanRef.get()不管在什么情況下會(huì)一直返回null

System.out.println(phantom.get());

?

// 當(dāng)GC發(fā)現(xiàn)了虛引用,GC會(huì)將phanRef插入進(jìn)我們之前創(chuàng)建時(shí)傳入的refQueue隊(duì)列

// 注意,此時(shí)phanRef所引用的obj對(duì)象,并沒(méi)有被GC回收,在我們顯式地調(diào)用refQueue.poll返回phanRef之后

// 當(dāng)GC第二次發(fā)現(xiàn)虛引用,而此時(shí)JVM將phanRef插入到refQueue會(huì)插入失敗,此時(shí)GC才會(huì)對(duì)obj進(jìn)行回收

Thread.sleep(200);

System.out.println(refQueue.poll());

}

這里特別需要注意:當(dāng)JVM將虛引用插入到引用隊(duì)列的時(shí)候,虛引用執(zhí)行的對(duì)象內(nèi)存還是存在的。但是PhantomReference并沒(méi)有暴露API返回對(duì)象。如NIO直接內(nèi)存的自動(dòng)回收,就使用到了sun.misc.Cleaner

?

public class Cleaner extends PhantomReference

{

}

JDK底層源碼查詢網(wǎng)站:http://www.docjar.com/html/api/sun/misc/Cleaner.java.html

5、小結(jié)

引用和引用隊(duì)列提供了一種通知機(jī)制,允許我們知道對(duì)象已經(jīng)被銷毀或者即將被銷毀。GC要回收一個(gè)對(duì)象的時(shí)候,如果發(fā)現(xiàn)該對(duì)象有軟、弱、虛引用的時(shí)候,會(huì)將這些引用加入到注冊(cè)的引用隊(duì)列中。軟引用和弱引用差別不大,JVM都是先把SoftReference和WeakReference中的referent字段值設(shè)置成null,之后加入到引用隊(duì)列;而虛引用則不同,如果某個(gè)堆中的對(duì)象,只有虛引用,那么JVM會(huì)將PhantomReference加入到引用隊(duì)列中,JVM不會(huì)自動(dòng)將referent字段值設(shè)置成null。

參考資料:

Java:對(duì)象的強(qiáng)、軟、弱和虛引用 ? ?http://zhangjunhd.blog.51cto.com/113473/53092/

Java 中的 Reference ? ? ? ? ? ? ?http://www.cnblogs.com/newcj/archive/2011/05/15/2046882.html

總結(jié)

以上是生活随笔為你收集整理的java中的4种reference的差别和使用场景(含理论、代码和执行结果)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。