转载请标明出处
本文出自[HCY的微博]

一、概述

Android内存的文章详见:http://blog.csdn.net/linghu_java/article/details/39480761
在Android的开发中,经常听到“内存泄漏”这个词。“内存泄漏”就是一个对象已经不需要再使用了,但是因为其它的对象持有该对象的引用,导致它的内存不能被回收。“内存泄漏”的慢慢积累,最终会导致OOM的发生,千里之堤,毁于蚁穴。所以在写代码的过程中,应该要注意规避会导致“内存泄漏”的代码写法,提高软件的健壮性。
本文将从发现问题、解决问题、总结问题的三个角度出发,循序渐进,彻底解决“内存泄漏”的问题。

二、内存泄漏的检查工具Heap

工欲善其事必先利其器,要检测“内存泄漏”的发生,需要借助DDMS中的Heap工具及MAT工具,Heap工具用于大致分析是否存在“内存泄漏”,而MAT工具则用于分析“内存泄漏”发生在哪里。

Heap工具的使用介绍

具体操作
1.在Devices设备列表中,找到你所在的设备,点击你想要监控的进程。
2.点击“Update Heap”按钮更新堆内存的情况。
3.点击“Heap”视图,查看内存的情况。
4.每次在Activity的退出和进入的时候点击“Cause GC”,手动调用GC释放应用的内存。
5.观察data oject那一行,每一次点击“Casue GC”的时候,观察Total Size的值,如果该值不断增加,则说明该应用程序存在“内存泄漏”。

我们先模拟一下内存泄漏,然后通过Heap工具来判断一下是否存在内存泄漏。
上一段存在内存泄漏的代码:

public class LeakAty extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.aty_leak);        testLeak();    }    /** * 测试内存泄漏的代码 */    private void testLeak() {        new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();    }

上述的代码存在内存泄漏,new Runnable(){}是一个非静态的匿名内部类,所以它会强引用创建它的外围对象LeakAty,我们来测试一下内存泄漏的过程,开启手机的方向旋转功能,不断地旋转手机,让LeakAty不断地创建新的实例。理论上如果不存在上述泄漏的代码,之前的Activity会在onDestory之后被回收内存。而一旦存在上述泄漏的代码,新创建的Ruannale实例会一直处于运行状态,它不会被回收,而它强引用的LeakAty当然也不会被回收,所以在屏幕不断旋转,之前创建的LeakAty就不会被释放,会导致旋转n次,内存中就存在n+1个的LeakAty实例。
Heap工具第一次按下Cause GC按钮的截图:

上图的data object的Total Size的大小为1.031M。经过多次的旋转屏幕之后,我们再看一下截图

Total Size变成了2.059M,从1.031M到2.059M,每次调用GC的过程中data object的总大小没有回落,所以可以证实上面的代码确实是存在内存泄漏的问题,那么泄漏发生在哪里?答案可以通过MAT工具来分析得到。

三、内存泄漏的分析工具MAT

要通过MAT分析,需要提供一个.hprof文件。我们可以通过”Dump HPROF file”按钮转存当前的堆内存信息。我们将其保存为1.hprof。

导出的1.hprof的格式需要通过..\sdk\tools\目录下的hprof-conv.exe工具进行转换才能被MAT成功导入,我们将其转换成out1.hprof

将out1.hprof导入到MAT工具中,File->Open Heap Dump…

点击左边的标签Overview,Actions->Histogram

在Histogram界面中,因为我们想要知道Activity是否泄漏了,所以输入关键词Activity,然后按下回车键。

之后便可以得到Activity的相关的搜索结果,下图的搜索结果中Activity的实例有7个。点击选中下图标红色框框的地方,右键->Merge Shortest Paths to GC Roots->exclude all phantom/weak/soft etc. references。排除虚引用、弱引用、软引用的实例,剩下的都是强引用实例。

从过滤出来的强引用的列表中,我们可以看到这七个实例都是被Thread所引用了。所以证实上面的代码确实存在内存泄漏。

四、本文总结

内存泄漏检测可以使用Heap工具,内存分析可以使用MAT工具。本文的案例中提到了一种内存泄漏的情况,就是非静态内部类的对象会强引用其外围对象,一旦这个非静态内部类的实例没有释放,它的外围对象也不会释放,所以就会造成内存泄漏。下篇将具体探讨一下,在Android的开发过程中,哪些写法容易造成内存泄漏,该如何解决?请阅读Android内存泄漏终极解决篇(下)。

五、附件

MAT工具下载见:MAT下载地址

更多相关文章

  1. android支持多行的radiogroup
  2. android adb工具
  3. Android(安卓)开发环境入门
  4. 【【【常用的ubuntu第三方工具及android命令(自存档)】】】二
  5. 【android测试】值得学习的android测试知识连接
  6. Android(安卓)获取内存信息
  7. Android(安卓)返回键连续点击两次退出应用
  8. Android(安卓)源码结构
  9. Android原生弹框的工具类AlertDialog,Dialog

随机推荐

  1. 送1万美元鼓励员工离职创业,亚马逊是疯了
  2. 零代码实现一对一表关系和无限主子表级联
  3. 20210401 微服务测试
  4. GAN毕业手册:从零到一构建自己的GAN模型
  5. JVM内存分配与回收
  6. 百度核心搜索面试
  7. Java 如何有效地避免OOM:善于利用软引用和
  8. 华为发布业界首款AI-Native数据库,挑动了
  9. 存储卡出现“文件或目录结构损坏且无法读
  10. web前端开发都用什么软件?