問題:
強(qiáng)引用、軟引用、弱引用、幻象引用有什么區(qū)別?具體使用場景是什么?
知識點(diǎn):
- 對象可達(dá)性
對象可達(dá)性對于我們理解JVM 可達(dá)性分析有重要作用,具體后續(xù)文章會談到。 - 引用隊列(ReferenceQueue)使用。
利用引用隊列,我們可以在對象處于相應(yīng)狀態(tài)時,執(zhí)行后期處理邏輯。例如:LeakCanary監(jiān)控內(nèi)存泄漏的源碼中:
//源碼地址 LeakCanary
com.squareup.leakcanary.RefWatcher
private void removeWeaklyReachableReferences() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
//do something
retainedKeys.remove(ref.key);
}
}
removeWeaklyReachableReferences 把已被回收的對象的 key 從 retainedKeys 移除,剩下的 key 都是未被回收的對象;LeakCanary分析可以參考文章:帶你學(xué)開源項目:LeakCanary- 如何檢測 Activity 是否泄漏
- Reachablity Fence
除了這四種基本引用類型,我們也可以通過底層API來達(dá)到引用的效果,這就是所謂的設(shè)置reachability fence。這里不做詳細(xì)介紹,有興趣的自己查看相關(guān)資料。
回答問題:
在Java語言中,除了基本數(shù)據(jù)類型以外,其他都是指向各類對象的對象引用,根據(jù)生命周期長短,通常分為四類:
強(qiáng)引用:我們正常new出來對象就是強(qiáng)引用,當(dāng)內(nèi)存不夠的時候,JVM寧可拋出異常,也不會回收強(qiáng)引用對象。對于一個普通的對象,如果沒有其他的引用關(guān)系,只要超過了引用的作用域或者顯示的將相應(yīng)(強(qiáng))引用賦值為null,就是可以被垃圾收集了,當(dāng)然具體回收時機(jī)還是要看垃圾收集策略。
軟引用(SoftReference):軟引用生命周期比強(qiáng)引用低,在內(nèi)存不夠的時候,會進(jìn)行回收軟引用對象。軟引用對象經(jīng)常和引用隊列(ReferenceQueue)一起使用,在軟引用所引用的對象被GC回收后,會把該引用加入到引用隊列中。通常用來實現(xiàn)內(nèi)存敏感的緩存。例如:Android圖片框架Fresco中就使用到了。
public class OOMSoftReference<T> {
SoftReference<T> softRef1;
SoftReference<T> softRef2;
SoftReference<T> softRef3;
public OOMSoftReference() {
softRef1 = null;
softRef2 = null;
softRef3 = null;
}
public void set(@Nonnull T hardReference) {
softRef1 = new SoftReference<T>(hardReference);
softRef2 = new SoftReference<T>(hardReference);
softRef3 = new SoftReference<T>(hardReference);
}
@Nullable
public T get() {
return (softRef1 == null ? null : softRef1.get());
}
public void clear() {
if (softRef1 != null) {
softRef1.clear();
softRef1 = null;
}
if (softRef2 != null) {
softRef2.clear();
softRef2 = null;
}
if (softRef3 != null) {
softRef3.clear();
softRef3 = null;
}
}
}
有興趣可以自己去查看源碼。
弱引用(WeakReference):弱引用生命周期比軟引用要短,在下一次GC的時候,掃描到它所管轄的區(qū)域存在弱引用的話,不管當(dāng)前內(nèi)存是否夠,都會進(jìn)行回收。(由于垃圾回收器是一個優(yōu)先級很低的線程,因此不一定會很快回收弱引用的對象)。弱引用和軟引用一樣,也會經(jīng)常和引用隊列(ReferenceQuene)一起使用,在弱引用所引用的對象被GC回收后,會把該引用加入到引用隊列中。經(jīng)常用在圖片緩存中。例如:ThreadLocal中所持用的靜態(tài)類ThreadLocalMap的Key值就用到了弱引用,防止內(nèi)存泄露(value可能存在內(nèi)存泄露,調(diào)用remove方法)。
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
有興趣的話,可以查看源碼,也可以參考文章:理解Java中的ThreadLocal。
幻象引用(PhantomReference):又叫虛引用,幻想引用僅僅是提供了一種確保對象被finalize后會處理某些事情,必須和引用隊列一起使用(ReferenceQuene)。比如上面一篇文章所說的Cleaner機(jī)制中就使用到了幻象引用,也可以用來跟蹤對象被垃圾回收器回收的活動,當(dāng)一個幻象引用關(guān)聯(lián)的對象被垃圾回收器回收之前收到一條系統(tǒng)通知。
參考:
- 帶你學(xué)開源項目:LeakCanary- 如何檢測 Activity 是否泄漏
- fresco部分源碼
- 理解Java中的ThreadLocal
- 極客時間APP核心技術(shù)第四講|強(qiáng)引用、軟引用、弱引用、幻象引用有什么區(qū)別?
聲明:此為原創(chuàng),轉(zhuǎn)載請聯(lián)系作者
作者:微信公眾號添加公眾號-遛狗的程序員 ,或者可以掃描以下二維碼關(guān)注相關(guān)技術(shù)文章。

當(dāng)然喜愛技術(shù),樂于分享的你也可以可以添加作者微信號:
