詳解Java中的四種引用類型(強(qiáng)軟弱虛)
強(qiáng)引用(StrongReference)
強(qiáng)引用指的就是代碼中普遍存在的賦值方式,比如A a = new A()
這種。強(qiáng)引用關(guān)聯(lián)的對象,永遠(yuǎn)不會被GC回收。
當(dāng)內(nèi)存空間不足的時候,java虛擬機(jī)寧愿拋出OutOfMemoryError
錯誤,是程序異常終止,也不會回收具有強(qiáng)引用的對象來解決內(nèi)存不足的問題
obj=null //幫助垃圾回收器回收這個對象
顯式地設(shè)置obj為null,或者說超出對象的生命周期范圍,則GC認(rèn)為該對象不存在引用,這時候就可以回收這個對象了,具體什么時候回收這要看GC的算法是怎么樣的。
當(dāng)一個方法的內(nèi)部有一個強(qiáng)引用,這個引用保存在棧中,而這個引用的內(nèi)容存放在堆中,當(dāng)這個方法運(yùn)行完成后就會退出方法棧,那么引用內(nèi)容也會跟著就會不存在了,這個Object就會被回收。但是如果個這個obj是一個全局變量的時候,就需要再不用的時候?qū)①x值為null,因?yàn)閺?qiáng)引用是不會被垃圾回收的
在ArrayList的clear方法中就用到了強(qiáng)引用
private transient Object[] elementData; public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) { elementData[i] = null; } size = 0; }
在 ArrayList 類中定義了一個私有的變量 elementData 數(shù)組,在調(diào)用方法清空數(shù)組時可以看到為每個數(shù)組內(nèi)容賦值為null。 不同于elementData = null,強(qiáng)引用仍然存在,避免在后續(xù)調(diào)用 add()等方法添加元素時,進(jìn)行重新的內(nèi)存分配。使用如 clear() 方法中釋放內(nèi)存的方法對數(shù)組中存放的引用類型特別適用,這樣就可以及時釋放內(nèi)存。
軟引用(SoftReference)
軟引用可以用SoftReference來描述,指的是那些有用但是不是必須要的對象。系統(tǒng)在發(fā)生內(nèi)存溢出前會對這類引用的對象進(jìn)行回收。
軟引用可以用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存
軟引用自身不會被垃圾回收,因?yàn)镚C Root還引用著,軟引用自身需要配合引用隊(duì)列來釋放。
String str = new String("abc"); // 強(qiáng)引用 SoftReference<String> softRef = new SoftReference<String>(str); // 軟引用 // 當(dāng)內(nèi)存不足時,等價于: if (JVM.內(nèi)存不足()) {//當(dāng)內(nèi)存不夠的時候就回收 str = null; // 轉(zhuǎn)換為軟引用 System.gc(); // 垃圾回收器進(jìn)行回收 }
軟引用在實(shí)際中有重要的應(yīng)用:
瀏覽器的后退按鈕。按后退時,這個后退時顯示的網(wǎng)頁內(nèi)容是重新進(jìn)行請求還是從緩存中取出呢?這就要看具體的實(shí)現(xiàn)策略了。
- 獲取頁面進(jìn)行瀏覽,瀏覽完成后就可以將頁面設(shè)置為軟應(yīng)用
- 當(dāng)點(diǎn)擊回退按鈕到先前瀏覽過的頁面后,判斷是否被垃圾回收機(jī)制回收了,沒有回收就直接用,如果回收了,就在重新構(gòu)建頁面
軟引用可以和一個引用隊(duì)列(ReferenceQueue)聯(lián)合使用,當(dāng)引用的對象被垃圾回收器回收后,JVM會自動把這個軟引用加入到和它相關(guān)的這個引用隊(duì)列中
弱引用(WeakReference)
弱引用可以用WeakReference來描述,他的強(qiáng)度比軟引用更低一點(diǎn),弱引用的對象下一次GC的時候一定會被回收,而不管內(nèi)存是否足夠。 不過,由于垃圾回收器是一個優(yōu)先級很低的線程,因此不一定會很快發(fā)現(xiàn)那些只具有弱引用的對象。
弱引用與軟引用的區(qū)別在于:只具有弱引用的對象擁有更短暫的生命周期。
String str = new String("abc"); //強(qiáng)引用 WeakReference<String> weakRef = new WeakReference<String>(str); // 弱引用 str = null; // 當(dāng)垃圾回收器進(jìn)行掃描回收時等價于: str = null; System.gc(); // 垃圾回收器進(jìn)行回收 // 下面的代碼會讓str再次變?yōu)橐粋€強(qiáng)引用: str = weakRef.get();
使用場景:
- 如果這個對象是偶爾的使用,并且希望在使用時隨時就能獲取到,但又不想影響此對象的垃圾收集,那么你應(yīng)該用弱引用來記住此對象。
- 當(dāng)你想引用一個對象,但是這個對象有自己的生命周期,你不想介入這個對象的生命周期,這時候你就可以使用弱引用。這個引用不會在對象的垃圾回收判斷中產(chǎn)生任何附加的影響。
弱引用可以和一個引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機(jī)就會把這個弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
虛引用(PhantomReference)
虛引用也被稱作幻影引用,是最弱的引用關(guān)系,可以用PhantomReference
來描述,他必須和ReferenceQueue
一起使用,同樣的當(dāng)發(fā)生GC的時候,虛引用也會被回收。
虛引用與其他幾種引用都不同,它并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
虛引用與軟引用和弱引用的一個區(qū)別在于: 虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個對象時,如果發(fā)現(xiàn)它還有虛引用,就會在回收對象的內(nèi)存之前,把這個虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
應(yīng)用場景:
- 程序可以通過判斷引用隊(duì)列中是否存在該對象的虛引用,來了解這個對象是否將要被回收??梢?strong>用來作為GC回收Object的標(biāo)志。
- 可以用虛引用來管理堆外內(nèi)存。
Reference和ReferenceQueue
四大引用的父類Reference和ReferenceQueue
在Reference中有5個非常重要的屬性:referent,next,discovered,pending,queue。
//5個非常重要的屬性 private T referent; /* Treated specially by GC */ volatile ReferenceQueue<? super T> queue; Reference next; transient private Reference<T> discovered; /* used by VM */ private static Reference<Object> pending = null;
可以把每個Reference看做一個節(jié)點(diǎn),多個Reference通過next,discovered,pending 進(jìn)行關(guān)聯(lián)
- referent就是Reference實(shí)際引用的對象。
- 通過next屬性,可以構(gòu)建ReferenceQueue。
- 通過discovered屬性,可以構(gòu)建Discovered List。
- 通過pending屬性,可以構(gòu)建Pending List。
四大狀態(tài)
上圖就是Reference 的四個狀態(tài)
//Reference的兩個構(gòu)造方法,一個帶隊(duì)列,一個不帶 Reference(T referent) { this(referent, null); } ? Reference(T referent, ReferenceQueue<? super T> queue) { this.referent = referent; this.queue = (queue == null) ? ReferenceQueue.NULL : queue; } ?
對于帶ReferenceQueue的Reference,GC會把要回收對象的Reference放到ReferenceQueue中,后續(xù)該Reference需要程序員自己處理 (調(diào)用poll方法) 。
不帶ReferenceQueue的Reference, 由GC自己處理,待回收的對象其Reference狀態(tài)會變成Inactive。
- 創(chuàng)建好了Reference,就進(jìn)入active狀態(tài)。
- active狀態(tài)下,如果引用對象的可到達(dá)狀態(tài)發(fā)送變化就會轉(zhuǎn)變成Inactive或Pending狀態(tài)。
- Inactive狀態(tài)很好理解,到達(dá)Inactive狀態(tài)的Reference狀態(tài)不能被改變,會等待GC回收。
- Pending狀態(tài)代表等待入Queue,Reference內(nèi)部有個ReferenceHandler,會調(diào)用enqueue方法,將Pending對象入到Queue中入Queue的對象,其狀態(tài)就變成了Enqueued。
- Enqueued狀態(tài)的對象,如果調(diào)用poll方法從ReferenceQueue拿出,則該Reference的狀態(tài)就變成了Inactive,等待GC的回收。
這就是Reference的一個完整的生命周期。
三個Queue/List
三個Queue/List:ReferenceQueue,discovered List和pending List
。
- ReferenceQueue它本質(zhì)是由Reference中的next連接而成的。用來存儲GC待回收的對象。
- pending List就是待入ReferenceQueue的list。
- discovered List這個有點(diǎn)特別,在Pending狀態(tài)時候,discovered List就等于pending List。 在Active狀態(tài)的時候discovered List實(shí)際上維持的是一個引用鏈。通過這個引用鏈,我們可以獲得引用的鏈?zhǔn)浇Y(jié)構(gòu),當(dāng)某個Reference狀態(tài)不再是Active狀態(tài)時,需要將這個Reference從discovered List中刪除。
總結(jié)
Java的四種引用的級別由高到低依次為:強(qiáng)引用 > 軟引用 > 弱引用 > 虛引用
回收時機(jī) | 用途 | 生存時間 | |
---|---|---|---|
強(qiáng) | 重來不會 | 對象的一般狀態(tài) | JVM停止運(yùn)行時終止 |
軟 | 內(nèi)存不足 時 | 聯(lián)合引用隊(duì)列構(gòu)造有效期短、占內(nèi)存大,生命周期長的對象的二級高速緩沖器(內(nèi)存不足的時候清空) | 內(nèi)存不足 時終止 |
弱 | 在垃圾回收時 | 聯(lián)合引用隊(duì)列構(gòu)造有效期短、占內(nèi)存大,生命周期長的對象的一級高速緩沖器(發(fā)生GC的時候清空) | GC運(yùn)行后終止 |
虛 | 在垃圾回收時 | 聯(lián)合引用隊(duì)列來跟蹤對象被垃圾回收器回收的活動 | GC運(yùn)行后終止 |
以上就是詳解Java中的四種引用類型(強(qiáng)軟弱虛)的詳細(xì)內(nèi)容,更多關(guān)于Java引用類型的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot中EasyExcel實(shí)現(xiàn)execl導(dǎo)入導(dǎo)出
本文主要介紹了SpringBoot中EasyExcel實(shí)現(xiàn)execl導(dǎo)入導(dǎo)出,實(shí)現(xiàn)了如何準(zhǔn)備環(huán)境、創(chuàng)建實(shí)體類、自定義轉(zhuǎn)換器以及編寫導(dǎo)入邏輯的步驟和示例代碼,感興趣的可以了解下2023-06-06springboot docker原理及項(xiàng)目構(gòu)建
這篇文章主要介紹了springboot docker原理及項(xiàng)目構(gòu)建,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11Java排序算法三之歸并排序的遞歸與非遞歸的實(shí)現(xiàn)示例解析
這篇文章主要介紹了Java排序算法三之歸并排序的遞歸與非遞歸的實(shí)現(xiàn)示例解析,文章通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08Spring學(xué)習(xí)筆記3之消息隊(duì)列(rabbitmq)發(fā)送郵件功能
這篇文章主要介紹了Spring學(xué)習(xí)筆記3之消息隊(duì)列(rabbitmq)發(fā)送郵件功能的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-07-07聊聊Spring?Cloud?Gateway過濾器精確控制異常返回問題
這篇文章主要介紹了Spring?Cloud?Gateway過濾器精確控制異常返回問題,本篇任務(wù)就是分析上述現(xiàn)象的原因,通過閱讀源碼搞清楚返回碼和響應(yīng)body生成的具體邏輯,需要的朋友可以參考下2021-11-11