LeakCanary的工作原理

Java四大引用

  • 強(qiáng)引用:絕不回收
  • 軟引用:內(nèi)存不足才回收
  • 弱引用:碰到就回收
  • 虛引用:等價(jià)于沒有引用,只是用來標(biāo)識(shí)下指向的對(duì)象是否被回收。

WeakReference類

弱引用, 當(dāng)一個(gè)對(duì)象僅僅被weak reference(弱引用)指向, 而沒有任何其他strong reference(強(qiáng)引用)指向的時(shí)候, 如果這時(shí)GC運(yùn)行, 那么這個(gè)對(duì)象就會(huì)被回收,不論當(dāng)前的內(nèi)存空間是否足夠,這個(gè)對(duì)象都會(huì)被回收

WeakReference繼承Reference,其中只有兩個(gè)構(gòu)造函數(shù):

 /**
     * 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);
    }
  • referent:被弱引用的對(duì)象,
  • ReferenceQueue:應(yīng)用隊(duì)列,在對(duì)象被回收后,會(huì)把弱引用對(duì)象,也就是WeakReference對(duì)象或者其子類的對(duì)象,放入隊(duì)列ReferenceQueue中,注意不是被弱引用的對(duì)象,被弱引用的對(duì)象已經(jīng)被回收了。
private void test() {
    // 創(chuàng)建一個(gè)對(duì)象(強(qiáng)引用)
    Object obj = new Object();
    // 創(chuàng)建一個(gè)弱引用,并指向這個(gè)對(duì)象,并且將引用隊(duì)列傳遞給弱引用
    WeakReference<Object> reference = new WeakReference(obj, queue);
   
    // gc一次看看
    System.gc();
    此時(shí)循環(huán)打印引用隊(duì)列為null
   
    while ((obj = queue.poll()) != null) {
        System.out.println(": " + obj);
    }
    // 設(shè)置obj為null,現(xiàn)在只有弱引用引用,可以被回收了
    obj = null;
    // 再進(jìn)行g(shù)c,此時(shí)obj應(yīng)該被回收了,那么queue里面應(yīng)該有這個(gè)弱引用了
    System.gc();
    // 再打印隊(duì)列不為
    Object obj;
    while ((obj = queue.poll()) != null) {
        System.out.println(": " + obj);
    }
}

LeakCanary工作原理

利用弱引用特性,檢測(cè)Activity 的內(nèi)存泄漏

  • LeakCanary.install(application);此時(shí)使用application進(jìn)行registerActivityLifecycleCallbacks,從而來監(jiān)聽Activity的何時(shí)被destroy。

  • 在onActivityDestroyed(Activity activity)的回調(diào)中, 使用一個(gè)弱引用WeakReference指向這個(gè)activity,并且給這個(gè)弱引用指定一個(gè)引用隊(duì)列queue,同時(shí)創(chuàng)建一個(gè)key來標(biāo)識(shí)該activity。

  • 然后將檢測(cè)的方法ensureGone()投遞到空閑消息隊(duì)列。

  • 當(dāng)空閑消息執(zhí)行的時(shí)候,去檢測(cè)queue里面是否存在剛剛的弱引用,如果存在,則說明此activity已經(jīng)被回收,就移除對(duì)應(yīng)的key,沒有內(nèi)存泄漏發(fā)生。

  • 如果queue里不存在剛剛的弱引用,則手動(dòng)進(jìn)行一次gc。

  • gc之后再次檢測(cè)queue里面是否存在剛剛的弱引用,如果不存在,則說明此activity還沒有被回收,此時(shí)已經(jīng)發(fā)生了內(nèi)存泄漏,直接dump堆棧信息并打印日志,否則沒有發(fā)生內(nèi)存泄漏,流程結(jié)束。

空閑消息被執(zhí)行的時(shí)候,大概率已經(jīng)發(fā)生過gc,所以可以檢測(cè)下gc后activity是否被回收。但是也可能還沒發(fā)生gc,那么此時(shí)activity沒有被回收是正常的,所以我們手動(dòng)再gc一下,確保發(fā)生了gc,再去檢測(cè)activity是否被回收,從而100%的確定是否發(fā)生了內(nèi)存泄漏。

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

相關(guān)閱讀更多精彩內(nèi)容

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