java虚引用作用_深入理解Java中的引用(二)——强软弱虚引用
深入理解Java中的引用(二)——強(qiáng)軟弱虛引用
在上一篇文章中介紹了Java的Reference類,本篇文章介紹他的四個(gè)子類:強(qiáng)引用、軟引用、弱引用、虛引用。
強(qiáng)引用(StrongReference)
強(qiáng)引用是我們?cè)诖a中最普通的引用。示例代碼如下:
Object o = new Object(); // 強(qiáng)引用
在JVM的GC算法中,如果一個(gè)對(duì)象具有強(qiáng)引用,那么JVM寧可拋出Out of Memory錯(cuò)誤,垃圾回收器也不會(huì)去回收這個(gè)對(duì)象。
當(dāng)在代碼里顯示的寫o = null,或者該對(duì)象的引用作用域是在一個(gè)函數(shù)里,代碼如下,當(dāng)線程調(diào)用完test,就會(huì)退出方法棧,引用不存在,垃圾回收器才會(huì)在某個(gè)時(shí)刻回收Object對(duì)象。
public void test(){
Object o = new Object(); // 強(qiáng)引用
}
軟引用(SoftReference)
如果一個(gè)對(duì)象有一個(gè)軟引用,那么在內(nèi)存足夠的情況下,該對(duì)象就不會(huì)被垃圾回收器回收。網(wǎng)上有很多資料說軟引用只會(huì)在內(nèi)存空間不夠用的情況下對(duì)象才會(huì)被回收。 那么什么時(shí)候才是內(nèi)存不夠用呢?
首先看一下SoftReference類的源碼可以看到有兩個(gè)字段。這兩個(gè)字段的作用已經(jīng)標(biāo)注,這與JVM GC有什么關(guān)系呢?
/**
* 記錄最近一次被GC的時(shí)間。
*/
static private long clock;
/**
* 每次調(diào)用get方法的時(shí)候更新
* 記錄當(dāng)前Reference最近一次被訪問的時(shí)間
*/
private long timestamp;
一起看一下HotSpot的源碼,對(duì)于軟引用的回收策略見下面should_clear_reference函數(shù)。
// The oop passed in is the SoftReference object, and not
// the object the SoftReference points to.
bool LRUMaxHeapPolicy::should_clear_reference(oop p,
jlong timestamp_clock) {
jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p);
assert(interval >= 0, "Sanity check");
// The interval will be zero if the ref was accessed since the last scavenge/gc.
if(interval <= _max_interval) {
return false;
}
return true;
}
上述代碼中interval表示當(dāng)前引用存活了多久。他的值就是對(duì)應(yīng)上述java代碼中的clock與timestamp相減。interval與_max_interval比較,如果大于 _max_interval,那么就和弱引用一樣處理,如果小于就當(dāng)做強(qiáng)引用處理。_max_interval的賦值函數(shù)如下:
// Capture state (of-the-VM) information needed to evaluate the policy
void LRUMaxHeapPolicy::setup() {
size_t max_heap = MaxHeapSize;
max_heap -= Universe::get_heap_used_at_last_gc();
max_heap /= M;
_max_interval = max_heap * SoftRefLRUPolicyMSPerMB;
assert(_max_interval >= 0,"Sanity check");
}
通過源碼可見首先是max_heap減去上次GC之后剩余堆大小,如果上次GC之后還有很多剩余空間,說明內(nèi)存空間不夠用了,那么max_heap的值就越小,相應(yīng)_max_interval也越小,軟引用就越可能被回收。
軟引用的一個(gè)作用是實(shí)現(xiàn)內(nèi)存敏感的高速緩存。比如瀏覽器的后退按鈕,
(1)如果網(wǎng)頁(yè)瀏覽結(jié)束就進(jìn)行內(nèi)容的回收,則按后退查看前面瀏覽過的頁(yè)面時(shí),需要重新構(gòu)建。
(2)如果將瀏覽過的網(wǎng)頁(yè)存儲(chǔ)到內(nèi)存中會(huì)造成內(nèi)存的大量浪費(fèi),甚至?xí)斐蓛?nèi)存溢出。
通過軟引用可以解決該問題
Browser prev = new Browser(); // 獲取頁(yè)面進(jìn)行瀏覽
SoftReference sr = new SoftReference(prev); // 瀏覽完畢后置為軟引用
if(sr.get()!=null){
rev = (Browser) sr.get(); // 還沒有被回收器回收,直接獲取
}else{
prev = new Browser(); // 由于內(nèi)存吃緊,所以對(duì)軟引用的對(duì)象回收了
sr = new SoftReference(prev); // 重新構(gòu)建
}
弱引用(WeakReference)
只具有弱引用的對(duì)象生命周期更短。當(dāng)垃圾回收器發(fā)現(xiàn)了只有弱引用的對(duì)象時(shí)候,無論內(nèi)存空間是否足夠,都會(huì)被GC回收。當(dāng)你偶爾需要引用某個(gè)對(duì)象,隨時(shí)能獲取該對(duì)象,但是不想介入該對(duì)象的生命周期的時(shí)候,就可以使用弱引用, 因?yàn)槿跻貌粫?huì)對(duì)對(duì)象的垃圾回收判斷產(chǎn)生附加的影響。
當(dāng)弱引用綁定的對(duì)象被垃圾回收的時(shí)候,JVM會(huì)把這個(gè)弱引用加入到相關(guān)聯(lián)的ReferenceQueue中。
這里拋出兩個(gè)問題:
(1)弱引用什么時(shí)候會(huì)被加入到ReferenceQueue中,由什么決定的呢?
(2)如果綁定的對(duì)象GC之后存活了下來,弱引用怎么知道這個(gè)對(duì)象的新地址呢?
第一種情況,GC掃描到只存在弱引用的時(shí)候就會(huì)把它放到鏈表里。還有第二種情況:一個(gè)對(duì)象既有強(qiáng)引用又有弱引用的情況
下面通過圖片來解釋上面兩個(gè)問題:
image.png
上圖表示C同時(shí)存在兩個(gè)引用:強(qiáng)引用A和弱引用B。
第一種情況:GC先掃描到A
這種情況下GC同時(shí)會(huì)掃描到C,A和C都會(huì)搬到Survivor區(qū)。然后掃描到B,發(fā)現(xiàn)B引用的C搬到到了新的Survivor,這個(gè)時(shí)候就把B也搬到Survivor,并把C的新地址更新到B,結(jié)果如下:
image.png
第二種情況:GC先掃描到B
GC還是會(huì)先把B放到ReferenceQueue中,由于C還是存活的,所以B會(huì)被搬到Survivor中。然后掃描到A,A和C都會(huì)搬到Survivor中,GC結(jié)束的時(shí)候B所指向的對(duì)象就不對(duì)了,如下圖所示
image.png
該情況下會(huì)重新遍歷ReferenceQueue,發(fā)現(xiàn)綁定的對(duì)象依然存活,C‘ 的指針是指向C的,于是就把B再指向C就可以了,同時(shí)因?yàn)镃依然存活,把B從ReferenceQueue中移除。新的地址空間如下圖所示:
image.png
具體過程可以查看海納知乎專欄。
虛引用(PhantomReference)
虛引用不會(huì)對(duì)對(duì)象的垃圾回收有任何附加影響,他與軟引用和弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。查看他的構(gòu)造方法可以看到必須與一個(gè)ReferenceQueue綁定,而且他的get方法返回的一直是null
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue super T> q) {
super(referent, q);
}
虛引用主要用在跟蹤對(duì)象垃圾回收的狀態(tài)。具體應(yīng)用會(huì)在在下一節(jié)講到DirectByteBuffer 與ThreadLoal回收的時(shí)候詳細(xì)分析。
總結(jié)
關(guān)于強(qiáng)引用、軟引用、弱引用與虛引用在垃圾回收時(shí)的區(qū)別可以用下圖表示:
image.png
下圖總結(jié)了四種引用在其他方面的區(qū)別:
image.png
總結(jié)
以上是生活随笔為你收集整理的java虚引用作用_深入理解Java中的引用(二)——强软弱虚引用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 判断是否是list_JAVA从
- 下一篇: python获取文件名不含后缀名_大部分