我们平常在开发Android应用程序的时候,稍有不慎就有可能产生OOM,虽然JAVA有垃圾回收机,但也不能杜绝内存泄露,内存溢出等问题,随着科技的进步,移动设备的内存也越来越大了,但由于Android设备的参差不齐,可能运行在这台设备好好的,运行在那台设备就报OOM,这些适配问题也是比较蛋疼的,比如我们平常运行着一个应用程序,运行的好好的,突然到某个Activity就给你爆出一个OOM的错误,你可能会以为是这个Activity导致的内存泄露,你会想到也有可能是内存有泄露吗?内存泄露就像一个定时炸弹,随时都有可能使我们的应用程序崩溃掉,所以作为一名Android开发人员,还是需要有分析内存泄露的能力,说道这里我们还是要说下什么是内存泄露,内存泄露是指有个引用指向一个不再被使用的对象,导致该对象不会被垃圾回收器回收。因此,垃圾回收器是无法回收内存泄露的对象。本文就使用DDMS(Dalvik Debug Monitor Server)和MAT(Memory Analyzer Tool)工具带大家来分析内存泄露问题。

工具的准备

DDMS是ADT自带的调试工具,有关DDMS的使用请参考http://developer.android.com/tools/debugging/ddms.html,而MAT的就需要我们自行安装Eclipse插件,安装方法我就不多说了,下面给出一个在线安装的地址:http://download.eclipse.org/mat/1.3/update-site/,MAT可以检测到内存泄露,降低内存消耗,它有着非常强大的解析堆内存空间dump能力。

如何检测内存泄露

1.使用DDMS检测内存泄露

打开Devices视图,选择我们需要分析的应用程序进程,点击Updata Heap按钮

然后在打开DDMS, 选择Heap标签,然后点击Cause GC按钮,点击Cause GC是手动触发JAVA垃圾回收器,如下图

如果我们要测试某个Activity是否发生内存泄露,我们可以反复进入和退出这个Activity, 再手动触发几次垃圾回收,观察上图中 data object这一栏中的 Total Size的大小是保持稳定还是有明显的变大趋势,如果有明显的变大趋势就说明这个Activity存在内存泄露的问题,我们就需要在具体分析。

2.使用Logcat检测内存泄露

当垃圾回收机在进行垃圾回收之后,会在Logcat中作相对于的输出,所以我们也可以通过这些信息来判断是否存在内存泄露问题

一,上面消息的第一个部分产生GC的原因,一共有四种类型
GC_CONCURRENT   当你的堆内存快被用完的时候,就会触发这个GC回收
GC_FOR_MALLOC  堆内存已经满了,同时又要试图分配新的内存,所以系统要回收内存
GC_EXTERNAL_ALLOC   在Android3.0 (Honeycomb)以前,释放通过外部内存(比如在2.3以前,产生的Bitmap对象存储在Native Memory中)时产生。Android3.0和更高版本中不再有这种类型的内存分配了。
GC_EXPLICIT  调用System.gc时产生,上图中就是点击Cause GC按钮手动触发垃圾回收器产生的log信息

二,freed 1413K表示GC释放了1434K的内存

三,20% free 9349K/11644K, 20%表示目前可分配内存占的比例,9349K表示当前活动对象所占内存,11644K表示Heap的大小

四,paused 8ms + 3ms, total 71ms,则表示触发GC应用暂停的时间和GC总共消耗的时间

有了这些log信息,我们就可以知道GC运行几次以后有没有成功释放出一些内存,如果分配出去的内存在持续增加,那么很明显存在内存泄露,如下存在内存泄露的Log信息

很明显Heap中空闲内存占总Heap的比例在缩小,Heap中活动对象所占的内存在增加。

内存泄露分析实战

下面是一个存在内存泄露的例子代码,这也是比较常见的一种内存泄露的方式,就是在Activity中写一些内部类,并且这些内部类具有生命周期过长的现象

  1. package com.example.memoryleak;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.app.Activity;
  5. import android.os.Bundle;
  6. public class LeakActivity extends Activity {
  7. private List<String> list = new ArrayList<String>();
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. //模拟Activity一些其他的对象
  12. for(int i=0; i<10000;i++){
  13. list.add("Memory Leak!");
  14. }
  15. //开启线程
  16. new MyThread().start();
  17. }
  18. public class MyThread extends Thread{
  19. @Override
  20. public void run() {
  21. super.run();
  22. //模拟耗时操作
  23. try {
  24. Thread.sleep(10 * 60 * 1000);
  25. } catch (InterruptedException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }
  30. }

运行例子代码,选择Devices视图,点击上面Updata Heap标签,然后再旋转屏幕,多重复几次,然后点击Dump HPROF file, 之后Eclipse的MAT插件会自动帮我们打开,如下图

我们看到下面有Histogram(直方图)他列举了每个对象的统计,Dominator Tree(支配树)提供了程序中最占内存的对象的排列,这两个是我在排查内存泄露的时候用的最多的

Histogram(直方图)

我们先来看Histogram, MAT最有用的工具之一,它可以列出任意一个类的实例数。它支持使用正则表达式来查找某个特定的类,还可以计算出该类所有对象的保留堆最小值或者精确值, 我们可以通过正则表达式输入LeakActivity, 看到Histogram列出了与LeakActivity相关的类

我们可以看到LeakActivity,和MyThread内部类都存在16个对象,虽然LeakActivity和MyThread存在那么多对象,但是到这里并不能让我们准确的判断这两个对象是否存在内存泄露问题, 选中com.example.memoryleak.LeakActivity,点击右键,如下图

Merge Shortest Paths to GC Roots 可以查看一个对象到RC  Roots是否存在引用链相连接, 在JAVA中是通过可达性(Reachability Analysis)来判断对象是否存活,这个算法的基本思想是通过一系列的称谓"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走得路径称为引用链,当一个对象到GC Roots没有任何引用链相连则该对象被判定为可以被回收的对象,反之不能被回收,我们可以选择 exclude all phantom/weak/soft etc.references(排查虚引用/弱引用/软引用等)因为被虚引用/弱引用/软引用的对象可以直接被GC给回收.

可以看到LeakActivity存在GC Roots链,即存在内存泄露问题,可以看到LeakActivity被MyThread的this$0持有。

除了使用Merge Shortest Paths to GC Roots 我们还可以使用

List object - With outgoing References   显示选中对象持有那些对象

List object - With incoming References  显示选中对象被那些外部对象所持有

Show object by class - With outgoing References  显示选中对象持有哪些对象, 这些对象按类合并在一起排序

Show object by class - With incoming References  显示选中对象被哪些外部对象持有, 这些对象按类合并在一起排序

Android 性能优化之使用MAT分析内存泄露问题的更多相关文章

  1. Android 性能优化之使用MAT分析内存泄露

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/42396507),请尊重他人的辛勤劳动成果,谢谢! 我们平常 ...

  2. 使用MAT分析内存泄露

    使用MAT分析内存泄露 对于大型服务端应用程序来说,有些内存泄露问题很难在测试阶段发现,此时就需要分析JVM Heap Dump文件来找出问题.随着单机内存越来越大,应用heap也开得越来越大,动辄十 ...

  3. Android性能优化之利用LeakCanary检测内存泄漏及解决办法

    前言: 最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来. ...

  4. Android 性能优化的方面方面都在这儿

    又到周六了,鸿洋的不定期的周六放送又来了~~这次来谈谈性能优化吧.大家在工作中或多或少都会拿自家的应用和竞品app做比对,不可避免的需要做一些app性能优化的活.很多时候可能是策略上的调整,不过还是有 ...

  5. 老李分享:Android性能优化之内存泄漏1

    老李分享:Android性能优化之内存泄漏   前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我 ...

  6. Android性能优化:手把手带你全面实现内存优化

      前言 在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的内存优化,希望你们会喜欢 目录   1. 定义 优化处理 应用程序的内存使用.空间占用 2. 作用 避免因不正确使用内 ...

  7. Android 性能优化之内存泄漏检测以及内存优化(中)

    https://blog.csdn.net/self_study/article/details/66969064 上篇博客我们写到了 Java/Android 内存的分配以及相关 GC 的详细分析, ...

  8. Android性能优化:手把手带你全面了解 内存泄露 & 解决方案

    . 简介 即 ML (Memory Leak)指 程序在申请内存后,当该内存不需再使用 但 却无法被释放 & 归还给 程序的现象2. 对应用程序的影响 容易使得应用程序发生内存溢出,即 OOM ...

  9. Android 性能优化 - 详解内存优化的来龙去脉

    前言 APP内存的使用,是评价一款应用性能高低的一个重要指标.虽然现在智能手机的内存越来越大,但是一个好的应用应该将效率发挥到极致,精益求精. 这一篇中我们将着重介绍Android的内存优化.本文的篇 ...

随机推荐

  1. TortoiseSVN 安装中文语言包,SVN中文语言包

    SVN中TortoiseSVN 是比较出门的一款SVN软件 TortoiseSVN 是Subversion 版本控制系统的一个免费开源客户端. 由于TortoiseSVN 默认是英文的:所以很多小伙伴 ...

  2. mysql安全

    安装MySql时,尽量选择别的端口(默认是3306),密码设复杂一点!在next的步骤中,注意不要选中"允许远程登录". Web漏洞检测及修复 http://wiki.open.q ...

  3. warning

    warning:statement has no effect [-Wunused-value]| 未能赋值,常见错误:m==1/for(i=0;i++;i<m)/

  4. Android - 安装 windows 7 安装 Android SDK 的时候出现的问题!(Connection to https://dl-ssl.google.com refused)

    Android - 安装 windows 7  安装 Android SDK 的时候出现的问题! 首先看到 Connection to https://dl-ssl.google.com refuse ...

  5. C/C++代码检视要点

    4.1.1       C/C++代码检视要点 代码检视技能属于开发人员的基本功,能够很大程度地反应出开发人员的能力水平,前面4.4.1节已经讲过提高评审检视的方法.下面以实际的C/C++语言方面的代 ...

  6. Python3 网络编程

    虽然大家现在对互联网很熟悉,但是计算机网络的出现比互联网要早很多. 计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM.Apple和Microsoft都有各自的 ...

  7. jQuery 选择器(转)

    jQuery 选择器 选择器 实例 选取 * $("*") 所有元素 #id $("#lastname") id="lastname" 的元 ...

  8. matlab2014在mac Yosemite下出现java空指针情况

    恢复方法为 使用xcode打开 /System/Library/CoreServices/SystemVersion.plist 将 ProductVersion 下的10.10或10.10.1改为1 ...

  9. mysql索引使用笔记

    1.使用explain语句查看性能mysql> explain select product_id from orders where order_id in (123, 312, 223, 1 ...

  10. Demo学习: CellDraw

    CellDraw 学习TUniStringGrid,为什么有些设置在web模式下无效? case TUniBitBtn(Sender).Tag of : UniStringGrid1.ColWidth ...