1. 程式人生 > >Android View/ViewRoot洩漏但Activity不洩漏問題

Android View/ViewRoot洩漏但Activity不洩漏問題

一般android裡的記憶體洩漏都是activity洩漏,測試方法通常是在back回到桌面的時候,檢視其activity,view例項物件是否為0來判斷,activity洩漏一般比較好定位,方法網上文章也有很多,都是通過檢視acitivity物件的gcroot路徑來看是誰引用了來定位問題。 最近在開發過程中遇到activity例項為0但是view/viewroot例項不為0的情況,這種情況定位問題跟前面的情況稍微有所不同,需要有更多的資訊來定位問題。遇到這種情況時,需要檢視ViewRoot的gcroot路徑來定位,瞭解android的都知道,ViewRoot的實現類為ViewRootImpl,可以檢視這個類的例項的gcroot路徑是怎樣的,來看例項:

class android.view.WindowManagerGlobal @ 0x71112f90
    sDefaultWindowManager android.view.WindowManagerGlobal @ 0x12d4a8d8
        mRoots java.util.ArrayList @ 0x13027908
            elementData java.lang.Object[10] @ 0x13027970
                [0] android.view.ViewRootImpl @ 0x13023058

乍一看,這裡面對我們沒有有用的資訊,因為這裡沒有任何跟我們程式碼相關的東西,這時就需要我們仔細分析一下了,因為這是ViewRoot洩漏,而ViewRoot是activity最頂層view相關的操作類,注意他不是一個真實的view,它只是用來做繪製相關的事情,真實的頂層view是叫DecorView,DecorView是window下的成員變數,每個Activity都有個Window,從這裡的分析可以試下看DecorView物件是不是還存在,可是很遺憾,搜尋了DecorView物件,發現例項為0。這說明Activity相關的View應該已經都被銷燬了,但為什麼View和ViewRoot還存在呢,難道不是Activity裡面的view?這時有個關鍵的線索是ViewRootImpl裡有個mView物件,它是加到WindowManager時的佈局物件,通過檢視這個mView物件可以看一下佈局到底是怎樣的。於是檢視ViewRootImpl的with outcoming refrence並檢視mView物件:

mView android.widget.LinearLayout @ 0x13023810
    <class, shadow$_kclass class android.widget.LinearLayout @ 0x7111da20
    mContext com.meizu.flyme.calculator.CalculatorApplication @ 0x12d4b088
    mResources android.content.res.Resources @ 0x12f79468
    mParent android.view.ViewRootImpl @ 0x13023058
    mAttachInfo android.view.View$AttachInfo @ 0x13023270
    mChildren android.view.View[12] @ 0x13023c68
        <class, shadow$_kclass class android.view.View[] @ 0x12d655c8
        [0] android.widget.TextView @ 0x13024070
            <class, shadow$_kclass class android.widget.TextView @ 0x7111a018
            mContext com.meizu.flyme.calculator.CalculatorApplication @ 0x12d4b088
            mResources android.content.res.Resources @ 0x12f79468
            mText, mTransformed java.lang.String 請輸入正確格式
            <class, shadow$_kclass class java.lang.String @ 0x70d96660
            value char[7] 請輸入正確格式

可以看到mView是一個LinearLayout,它的mChildren裡有一個TextView,TextView的value是“請輸入正確格式”,用這個文字去程式碼搜尋裡,終於找到,原來是彈的Toast。至此,我們終於找到原因: 原來是Toast引發了記憶體洩漏,因為Toast並不用依附在Activity,所以我們看到acitvity例項為0,DecorView例項也為0,這又是個android框架裡的記憶體洩漏!另外我們在查詢記憶體洩漏問題時可以多檢視物件的成員變數資訊,看一下有沒有跟我們程式碼裡可以關聯起來的,這是比較重要的思路!