強(qiáng)引用、軟引用、弱引用、幻象引用再不理解就晚了

問題:

強(qiáng)引用、軟引用、弱引用、幻象引用有什么區(qū)別?具體使用場景是什么?

知識點(diǎn):

  1. 對象可達(dá)性
    對象可達(dá)性對于我們理解JVM 可達(dá)性分析有重要作用,具體后續(xù)文章會談到。
  2. 引用隊列(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 是否泄漏

  1. 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)通知。

參考:

聲明:此為原創(chuàng),轉(zhuǎn)載請聯(lián)系作者


作者:微信公眾號添加公眾號-遛狗的程序員 ,或者可以掃描以下二維碼關(guān)注相關(guān)技術(shù)文章。

qrcode_for_gh_1ba0785324d6_430.jpg

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

WXCD.jpeg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容