一般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.xxx.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.xxx.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框架里的内存泄漏!另外我们在查找内存泄漏问题时可以多查看对象的成员变量信息,看一下有没有跟我们代码里可以关联起来的,这是比较重要的思路!