一篇文章学会定位内存泄漏

在日常开发中,不可避免的会碰到内存泄漏问题,本片文章作为记录自己在工作中如何使用工具发现内存泄漏,定位内存泄漏。

工具:leakcanary库,Android Profiler工具,MAT工具。

leakcanary库

leakcanary库是Square出品的,帮助我们在开发中及时发现程序中内存的内存泄漏问题,例如某个Activity退出时,该Activity内占用的资源应该全部被释放。但是若有资源被占用未被释放,就会导致内存泄漏,这时leakcanary会帮我们进行GC Root可达性分析,并将内存泄漏的原因通过通知栏提示用户。如图:

安卓内存分析1.png

点击右侧的 + 号展开详细日志,然后定位具体的内存泄漏原因,如果通过该日志难以定位。那么接下来就借助 Android Profiler的内存分析。通过leakcanary定位到内存分析发生在 RecodeVoiceWebViewAct页面,然后只要使用 Android Profiler分析该页面。

Android Profiler 工具

Android Profiler 是谷歌在Android Studio3.0推出的性能分析工具,取代了之前的 Android Monitor 工具。对于该工具的详细介绍,参考该文 官方文档。本文只介绍如何使用它的内存分析工具这块。首先看一张分析结果图,然后说明如何检测该页面的内存泄漏。

image

上图的标注:

(1) 选取的当前的分析的进程。

(2) 手动进行GC

(3) 点击该按钮会在左侧(7)处生成hprof文件

(4) 选取该段的内存,进行分析。

(5) 显示该类的实例,下方的Call Stack 显示该实例分配的线程

(6)显示需要进行内存分析的类

上文知道,我们已经定位内存泄漏发生在该页面,然后按照如下步骤进行分析:

  1. 打开 Android Profiler 选取app进程,选择MEMORY该选项。然后对该页面进行几次反复的开启关闭,然后回到上一个页面时,

  2. 点击(2)按钮进行 GC ,然后选取 GC 之后的这段内存进行分析。选取这段 GC,是由于该页面在这段内存中已经关闭,正常来讲在这段内存中不会存在该页面的实例。但是选取这段内存之后,查看实例的分配情况,发现在这段内存中还是存在该页面的实例。说明该页面确实发生了内存泄漏,点击(6)处的该类,在右侧显示实例窗口。点击实例,可以通过下方的 Call Stack 查看具体内存泄漏的原因。有些原因可能通过经验可以判断出来大致的原因,但是有些可能需要进一步通过下一步介绍的 MAT 工具进行准确定位。

MAT工具

MAT 是分析 Java 堆数据的专业工具,用它也可以定位内存泄漏的具体原因。用它之前需要将之前用Android Profiler 分析的那段内存生成一个hprof 格式的文件,但是这个文件不能直接用,需要通过sdk自带的工具 hprof-conv.exe (sdk/platform-toos下)对Android Studio 生成的hprof 文件转化成MAT 可以使用的 hprof 文件。在上文的 Android Profiler 分析的结果图中点击(3)处的按钮生成 hprof 文件。然后使用 hprof-conv.exe 对该文件进行转化。然后用 MAT工具打开转化后的文件。

  1. 筛选进行分析的对象

    image

    一般MAT中使用最多的是Histogram选项,点击图示指向的按钮,打开Histogram,然后在表格的第一行输入需要进行分析的类名称。

  2. 右键点击筛选出该选项,显示菜单,选择 list objects ->with incoming refs 项。显示该类的实例

    image
  3. 右健 该实例,菜单选择Path to GC Roots-->exclue all phantom/weak/soft etc. reference项。

image

从上图可以看出由于存在GCRoot,因此该对象不会被回收,并导致内存泄漏。从结果可以看到 RecodeVoiceWebViewAct的实例被util包下的VoiceEngineHelper类中的一个任务线程持有。因此只要在页面关闭时,停止该任务线程就可以解决。

总结

上面提供了三种发现定位内存泄漏的工具,对于容易定位的内存泄漏,可以直接使用leakcanary库以及Android Profiler 定位内存泄漏的地方,对于稍微复杂的需要用MAT工具通过定位具体的内存泄漏的原因。

你可能感兴趣的:(一篇文章学会定位内存泄漏)