Java強軟弱虛引用Reference

Java強軟弱虛引用Referencehtml

本文目的:深刻理解Reference

本文定位:學習筆記

學習過程記錄,加深理解,提高文字組合表達能力。也但願能給學習Reference的同窗一些靈感java

源碼說明

源碼基於jdk1.8.0_111:api

  • ReferenceQueue 源碼160行左右
  • Reference 源碼300行左右
  • SoftReference、WeakReference、PhantomReference繼承於Reference,代碼量都極少

由代碼量上也能夠初步判斷,Java引用,並不太複雜緩存

java.lang.ref包

Package java.lang.ref:網絡

提供引用對象類,它支持與垃圾收集器進行有限程度的交互。oracle

Provides reference-object classes, which support a limited degree of interaction with the garbage collector. --oracle.comless

java.lang.ref包中提供了幾個類:SoftReference類、WeakReference類和PhantomReference類,它們分別表明軟引用、弱引用和虛引用。ReferenceQueue類表示引用隊列,它能夠和這三種引用類聯合使用,以便跟蹤Java虛擬機回收所引用的對象的活動。ide

強引用

  • 強引用能夠直接訪問目標對象。
  • 強引用所指向的對象在任什麼時候候都不會被系統回收。JVM寧願拋出OOM異常,也不會回收強引用所指向的對象。
  • 強引用可能致使內存泄露。

軟引用SoftReference

SoftReference:軟引用–>當虛擬機內存不足時,將會回收它指向的對象;須要獲取對象時,能夠調用get方法。函數

能夠經過java.lang.ref.SoftReference使用軟引用。一個持有軟引用的對象,不會被JVM很快回收,JVM會根據當前堆的使用狀況來判斷什麼時候回收。當堆的使用率臨近閾值時,纔會回收軟引用的對象。學習

軟引用應用場景

例如從網絡上獲取圖片,而後將獲取的圖片顯示的同時,經過軟引用緩存起來。當下次再去網絡上獲取圖片時,首先會檢查要獲取的圖片緩存中是否存在,若存在,直接取出來,不須要再去網絡上獲取。

注意避免軟引用獲取對象爲null

在垃圾回收器對這個Java對象回收前,SoftReference類所提供的get方法會返回Java對象的強引用,一旦垃圾線程回收該Java對象以後,get方法將返回null。因此在獲取軟引用對象的代碼中,必定要判斷是否爲null,以避免出現NullPointerException異常致使應用崩潰。

軟引用SoftReference源碼

public class SoftReference<T> extends Reference<T> {

    /**
     * Timestamp clock, updated by the garbage collector
     */
    static private long clock;

    /**
     * Timestamp updated by each invocation of the get method.  The VM may use
     * this field when selecting soft references to be cleared, but it is not
     * required to do so.
     */
    private long timestamp;

    /**
     * Creates a new soft reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new soft reference will refer to
     */
    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }

    /**
     * Creates a new soft reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new soft reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     *
     */
    public SoftReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
        this.timestamp = clock;
    }

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>.
     *
     * @return   The object to which this reference refers, or
     *           <code>null</code> if this reference object has been cleared
     */
    public T get() {
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }

}
能夠看到SoftReference有一個類變量clock和一個變量timestamp,這兩個參數對於SoftReference相當重要。
  • clock:記錄了上一次GC的時間。這個變量由GC(garbage collector)來改變。
  • timestamp:記錄對象被訪問(get函數)時最近一次GC的時間。
那麼這兩個參數有什麼用?
  • 咱們知道軟引用是當內存不足時能夠回收的。可是這只是大體狀況,實際上軟應用的回收有一個條件:
  • clock - timestamp <= free_heap * ms_per_mb
  • free_heap是JVM Heap的空閒大小,單位是MB
  • ms_per_mb單位是毫秒,是每MB空閒容許保留軟引用的時間。Sun JVM能夠經過參數-XX:SoftRefLRUPolicyMSPerMB進行設置
舉個例子:
  • 目前有3MB的空閒,ms_per_mb爲1000,這時若是clock和timestamp分別爲5000和2000,那麼
  • 5000 - 2000 <= 3 * 1000
  • 條件成立,則該次GC不對該軟引用進行回收。
  • 因此每次GC時,經過上面的條件去判斷軟應用是否能夠回收並進行回收,即咱們一般說的內存不足時被回收。

弱引用WeakReference

若是一個對象只具備弱引用,那麼在垃圾回收器線程掃描的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程,所以不必定會很快發現那些只具備弱引用的對象。

弱引用也能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

應用場景示例

Android中的Handler

注意避免軟引用獲取對象爲null

同軟引用SoftReference

弱引用WeakReference源碼

public class WeakReference<T> extends Reference<T> {

    /**
     * Creates a new weak reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new weak reference will refer to
     */
    public WeakReference(T referent) {
        super(referent);
    }

    /**
     * Creates a new weak reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new weak reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     */
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

沒有其餘代碼,GC時被回收掉。

虛引用

虛引用是全部引用類型中最弱的一個。一個持有虛引用的對象,和沒有引用幾乎是同樣的,隨時均可能被垃圾回收器回收。當試圖經過虛引用的get()方法取得強引用時,老是會失敗。而且,虛引用必須和引用隊列一塊兒使用,它的做用在於跟蹤垃圾回收過程。 當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在垃圾回收後,銷燬這個對象,獎這個虛引用加入引用隊列。

使用場景

未遇到

虛引用PhantomReference源碼

public class PhantomReference<T> extends Reference<T> {

    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * <code>null</code>.
     *
     * @return  <code>null</code>
     */
    public T get() {
        return null;
    }

    /**
     * Creates a new phantom reference that refers to the given object and
     * is registered with the given queue.
     *
     * <p> It is possible to create a phantom reference with a <tt>null</tt>
     * queue, but such a reference is completely useless: Its <tt>get</tt>
     * method will always return null and, since it does not have a queue, it
     * will never be enqueued.
     *
     * @param referent the object the new phantom reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     */
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}
  • 能夠看到get函數返回null,正如前面說得虛引用沒法獲取對象引用
  • 同時能夠看到虛引用只有一個構造函數,因此必須傳入ReferenceQueue對象。
  • 前面提到虛引用的做用是判斷對象是否被回收,這個功能正是經過ReferenceQueue實現的。

ReferenceQueue

實現了鏈表結構的隊列

當系統要回收Reference持有的對象引用referent的時候,Reference的enqueue函數會被調用,而在這個函數中調用了ReferenceQueue的enqueue函數。

Reference與引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

參考

對本文有什麼建議(內容、寫做風格等),歡迎留言提出,感謝!

相關文章
相關標籤/搜索