备份

来源:互联网 发布:武汉ui知乎 编辑:程序博客网 时间:2024/05/19 17:26

“A small leak will sink a great ship.” - Benjamin Franklin

千里之堤, 毁于蚁穴。 -- 《韩非子·喻老》


        LeakCanary是一款强大而易用的内存检测工具,感谢Mars组、玲泉MM、佑荣GG一起推进这个工具的引入。 本周在跟进将内存泄露检测工具LeakCanary接入MM项目的事情,和大家分享下这个过程中学习内容和遇到的问题,希望对大家有帮助。

       1、内存泄露

        Java中的每个对象都有着有限的生命周期。当这些对象所要做的事情完成了,我们希望他们会被回收掉。但是如果还存在(一个或者多个)这个对象的引用,那么当这个对象生命周期结束后,它是不会被回收的。它还会占用内存,这就造成了内存泄露。如果内存泄露持续累加,内存很快被耗尽。比如,当 Activity.onDestroy 被调用之后,activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。但是,如果有一个后台线程持有这个 activity 的引用,activity 对应的内存就不能被回收。这最终将会导致内存耗尽,然后会出现OutOfMemoryError错误 而 crash。

       2、使用LeakCanary进行内存泄露检测的一个例子(LeakCanary项目中提供的例子) :

<code class="java" style="padding: 0px; font-family: courier, 'courier new', fixed-width; border: 0px; display: block; overflow-y: auto; font-size: 13px; margin: 0px; line-height: 22px; vertical-align: baseline;"><span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">class</span><span class="class" style="color: rgb(68, 85, 136); font-weight: bold;"> <span class="nc" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;"><span class="title">Cat</span></span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">{</span></span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;"></span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">}</span><span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">class</span><span class="class" style="color: rgb(68, 85, 136); font-weight: bold;"> <span class="nc" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;"><span class="title">Box</span></span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">{</span></span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;"></span>  <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">Cat</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">hiddenCat</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">;</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">}</span><span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">class</span><span class="class" style="color: rgb(68, 85, 136); font-weight: bold;"> <span class="nc" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;"><span class="title">Docker</span></span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">{</span></span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;"></span>  <span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">static</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">Box</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">container</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">;</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">}</span><span class="c1" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: italic; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: rgb(153, 153, 136);">// ...</span><span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">Box</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">box</span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">=</span> <span class="k" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">new</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">Box</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">();</span><span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">Cat</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">schrodingerCat</span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">=</span> <span class="k" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">new</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">Cat</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">();</span><span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">box</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">.</span><span class="na" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: rgb(0, 128, 128);">hiddenCat</span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">=</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">schrodingerCat</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">;</span><span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">Docker</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">.</span><span class="na" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: rgb(0, 128, 128);">container</span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">=</span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">box</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">;</span></code>

然后新建一个refwatcher实例,让它来检测schrodingerCat 对象是否存在内存泄露

<code class="java" style="padding: 0px; font-family: courier, 'courier new', fixed-width; border: 0px; display: block; overflow-y: auto; font-size: 13px; margin: 0px; line-height: 22px; vertical-align: baseline;"><span class="c1" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: italic; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: rgb(153, 153, 136);">// We expect schrodingerCat to be gone soon (or not), let's watch it.</span><span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">refWatcher</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">.</span><span class="na" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: rgb(0, 128, 128);">watch</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">(</span><span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">schrodingerCat</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">);</span></code>

当内存泄露问题被检测到时,LeakCanary会给出一份很详细的leak track报告。

<code class="text" style="padding: 0px; font-family: courier, 'courier new', fixed-width; border: 0px; display: block; overflow-y: auto; font-size: 13px; margin: 0px; line-height: 22px; vertical-align: baseline;">* GC ROOT <span class="keyword" style="font-weight: bold;">static</span> Docker.container* references Box.hiddenCat* leaks Cat instance</code>

    而要将LeakCanary添加到项目中进行监测的方法也很便捷:在项目中的Application的onCreate()方法中添加一行代码就可以了。然后LeakCanary就会自动侦测到activity的内存泄露情况了。

<code class="java" style="padding: 0px; font-family: courier, 'courier new', fixed-width; border: 0px; display: block; overflow-y: auto; font-size: 13px; margin: 0px; line-height: 22px; vertical-align: baseline;"><span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">public</span> <span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">class</span><span class="class" style="color: rgb(68, 85, 136); font-weight: bold;"> <span class="nc" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;"><span class="title">ExampleApplication</span></span> <span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;"><span class="keyword" style="color: rgb(51, 51, 51);">extends</span></span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;"><span class="title">Application</span></span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">{</span></span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;"></span>  <span class="nd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">@Override</span> <span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">public</span> <span class="kt" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline; color: rgb(68, 85, 136);"><span class="keyword" style="color: rgb(51, 51, 51);">void</span></span> <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">onCreate</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">()</span> <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">{</span>    <span class="kd" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">super</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">.</span><span class="na" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: rgb(0, 128, 128);">onCreate</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">();</span>    <span class="n" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline;">LeakCanary</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">.</span><span class="na" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; vertical-align: baseline; color: rgb(0, 128, 128);">install</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">(</span><span class="k" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">this</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">);</span>  <span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">}</span><span class="o" style="margin: 0px; padding: 0px; border: 0px; font-family: inherit; font-style: inherit; font-variant: inherit; font-weight: bold; line-height: inherit; vertical-align: baseline;">}</span></code>

3、项目接入时遇到的一些问题总结:      

        玲泉MM给出了LeakCanary接入项目中的详细文档,而佑荣GG提供了自动化插桩工具,这使得接入工作能够很方便的进行。然而,本小白在工具引入还是遇到了一些问题,感谢两位大牛的悉心指导,也把问题在这里记录下:

      1)配置cfg文件时需要注意的问题:

           leakcanary.cfg文件主要是用来配置插桩工具使用的相关参数,包括项目引用路径,需要排除的Activity的列表项,在AndroidManifest增加到application xml节点的service代码,以及按照和监控所需的代码块等信息。其中需要配置的是需要排除的Activity列表。由于应用的启动Activity和MainActivity会在插桩代码运行之前就启动,如果对LauncherActivity和MainActivity进行插桩的话就会导致程序出错。需要在配置文件中将不需要进行插桩的Actiivty(主要是启动Activity和MainActivity)列举出来。

       2)乱码问题:

             好容易才搞清楚需要配置的内容。使用插桩工具进行代码插入时出现以下问题。(图带水印是因为我先写在CSDN,又粘过来的。。。。)

              

             看样子是乱码问题。开始是使用记事本打开的cfg文件。后来玲泉MM建议用submite打开,问题解决。Windows下记事本的默认编码方式为ASCII,而cfg文件应该是UTF-8~~

        3)由一个逗号引发的问题

代码插入完成之后,编译过程中报错,有好长好长的问题列表,这里就不列出来吓大家了。后来分析代码发现是进行代码插桩的时候新加入的代码位置出了问题。由于监测函数是放在onDestroy()函数中的,而默认的插入规则是将代码插入到最后语句之后(分号之后);而这个函数居然在函数体结束之后带着分号(而且不会报错,好神奇的Java语言)。要感谢佑荣GG帮忙排查问题。

           

         4)编译过程中路径引用问题:

         开始时Properties文件如下:



           

           编译提示找不到依赖库文件。在编译配置文件中需要加入相应的编号才可以使用库工程的代码及资源的。修改后即可编译通过。

           

          Finally,LeakCanary终于接入了MM项目中。在这个过程中接触了内存泄露、工程编译的一些知识,也感受到了技术牛人们分析问题、定位问题的能力,和很厉害的编程能力。向他们致敬,向他们学习~~


0 0
原创粉丝点击