作为一个Android新手小白,刚到新公司,最近的工作就是在学习解各类Bug。转型之初,面临各种新知识,会有压力,但是学习的过程是快乐的。

  上周刚遇上一类bug,就是应用的内存泄漏问题。最终通过前辈的指点,用了两天的时间(包括今天),来解决了这个问题,并最终发现了Android原生代码的bug(值得开心......)。因此将学习的过程总结出来,可以供像我一样的新人参考学习。

一. 问题发现的背景

   QA测试发现,多次打开Android系统中设置功能里的某个Activity时,其占用的资源未能释放,并且在两三百次的重复操作后,设置应用发生了Crash的现象。

   崩溃的原因是OOM问题,即占用的资源因未能被GC回收,导致内存不足,抛出了OOM(Out of Memory)的异常,应用发生Crash。

   因此下一步就是RD来解决问题啦!

二. 需要准备/掌握的工具

   没有工具的配合,你很难轻松的应对和解决问题。经过前辈的指导后,开始入手学习使用解此类问题的一系列工具。

1. Adb Shell 命令

     Android新手入门一定先从Adb开始,Adb全称是Android debug bridge,提供很多操作手机的命令,有了它,可以方便的debug问题。这里我们使用的命令如下,

     A. adb shell

进入adb shell,执行以下命令

     B. am start -a "xxx" -d "xxx"

通过activity manager打开activity,方便多次测试,调查进程内存占用情况

     C. dumpsys meminfo xxx

查看进程的内存占用情况,xxx为包名

   2. DDMS + MAT工具

DDMS全称是Dalvik Debug Monitor Service,一般我用它来查看即时log,这里的作用是使用DDMS来生成hprof文件,hprof是Android进程的heap快照,有了它,可以来研究heap中存在哪些object,以及object的引用,研究为何GC没有回收对象的原因。

而MAT工具,正是由Eclipse提供的,能方便分析hprof文件的工具。MAT全称是Memory Analyzer Tool,内存分析工具,安装方式是在Eclipse中,选择install new software,然后提供插件的网址,选择安装即可。

   因此这里我们的思路是,通过Adb shell命令来测试并重现问题,然后用DDMS来抓取heap快照,使用MAT来分析heap快照,从来对照代码解决问题。

三. 解决此内存泄漏问题的过程

   1. 重现问题,通过am start命令直接打开此Activity,然后按手机的返回键,多次重复此过程

   2. 在步骤一的过程中,每次都使用dumpsys meminfo com.android.settings命令,来观察heap中Activity的数量。

     正常的情况下,Activity的值应该为0或1,不应该持续增长,因为按返回后,如果不存在内存泄漏,无用的Activity对象会被GC(垃圾回收)给回收掉。

     但这里,因为有问题存在,我观察到的现象是,Activity的数量一直在增长。如下图所示,heap中Activity的数量变化:

     步骤一操作1次,

操作2次,

操作5次,

可以明显的看到问题的发生,即在我们每次操作过程中,Activity虽然已经通过返回键,不予显示,但是占用的资源未能被GC回收,每次操作都会生成一个新的不会且不会被释放的Activity对象,发生了内存泄漏!

因此下一步要来解决问题。

   3. 使用DDMS+MAT发现线索,解决问题

既然现场已经重现,此时我们需要用DDMS来生成hprof文件,这里提到一点,如果你使用的都是Eclipse里安装的DDMS与MAT工具,在DDMS中点击生成hprof文件,会自动关联MAT,使用MAT打开此文件。

DDMS生成hprof文件,点击下图中的2个绿色按钮,如下,

MAT打开hprof文件,打开时建议选择第一项,如下,

之后打开后,就能分析heap文件啦。这里我们选择,点击Dominator Tree,它能列出heap中最大的对象们,

然后在打开的页面中,选择你测试时发现问题的Activity(可以使用关键词来过滤结果),这里出问题的Activity是,AppDrawOverlaySettingsActivity(Android原生代码),其对应的Fragment是DrawOverlayDetails。由于我们操作了5次,可以发现heap中的5个对象存在,都没有被释放。

   

这时要分析其未被释放的原因,要使用到MAT的功能来分析对象的引用,因为强引用的对象不会被GC回收。既然这个Activity对象一直存在,就说明一定是有引用存在,导致其未被GC回收。

     我的做法是,右击object,点击Merge Shortest Paths to GC Roots -> exclude all phantom/week/soft etc. preferences(因为要排除弱引用,以及软引用,这些引用包含的对象都会被GC回收,对我们没有参考价值)。

     之后便可以发现原因了,

     通过查看其引用,发现存在一个可疑的mSession变量,它属于Activity的父类,在类中使用了当前的对象,但是一直未能释放,因此这就是问题的原因,导致GC未能回收资源。

     知道原因后,解决的方法便很简单,就是在按返回键,触发的onStory或onDetach方法中,释放此mSession对象。最终便能解决问题。

    @Override
public void onDestroy() {
super.onDestroy();
mSession.release();
}

最后提交修改,在新的apk测试中,通过Adb shell命令测试发现,Activity数量已维持正常,内存泄漏的问题便也已解决。

最后总结,解决内存泄漏的问题,熟练使用命令和工具很重要。有了它们的帮助,能快速的找到线索,再到代码中去发现问题。当然复杂的问题,远没有本文中解决的过程简单,但是对于新手来说,学习此方法步骤会有很大帮助!

                                    - Kevin Song

                                    2016年5月9日

Android - 通过真实案例学习解内存泄漏问题,最终发现Android原生Bug的更多相关文章

  1. Android开发常见的Activity中内存泄漏及解决办法

    上一篇文章楼主提到由Context引发的内存泄漏,在这一篇文章里,我们来谈谈Android开发中常见的Activity内存泄漏及解决办法.本文将会以“为什么”“怎么解决”的方式来介绍这几种内存泄漏. ...

  2. 5个Android开发中比较常见的内存泄漏问题及解决办法

    android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了.   内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统 ...

  3. Android Weak Handler:可以避免内存泄漏的Handler库

    这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! android使用java作 ...

  4. Android开发从GC root分析内存泄漏

    我们常说的垃圾回收机制中会提到GC Roots这个词,也就是Java虚拟机中所有引用的根对象.我们都知道,垃圾回收器不会回收GC Roots以及那些被它们间接引用的对象.但是,对于GC Roots的定 ...

  5. Android性能优化之常见的内存泄漏

    前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我们可以借助LeakCanary.MAT等工具来检 ...

  6. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(中)- IOS不为人知的Bug

    前言: 话说昨晚还是前晚,写了一篇:讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(上) 文章写到最后时,多了很多莫名奇妙的问题!!! 为了解决了这些莫名奇妙的问题,我又战斗了2 ...

  7. Android引导页过多导致OOM内存泄漏

    摘要:前几天推广我们APP的时候,有些手机加载引导页的时候会闪退或崩溃,在Bugly显示是OOM异常.    然后Bugly上面显示的解决方案是: 该异常表示未能成功分配字节内存,通常是因为内存不足导 ...

  8. Android(java)学习笔记68:使用proguard混淆android代码

    1. 当前是有些工具比如apktool,dextojar等是可以对我们android安装包进行反编译,获得源码的.为了减少被别人破解,导致源码泄露,程序被别人盗取代码,等等.我们需要对代码进行混淆,a ...

  9. Android - 看似内存泄漏,实则不是,记一次内存泄漏的案例分析

    APP中常常会存在内存泄漏的问题,一个简单的测试方法是,多次进入和退出同一页面(Activity),使用adb shell中的dumpsys meminfo com.android.settings ...

随机推荐

  1. Halum UVA - 11478 差分约束

    输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 复制 2 1 1 2 10 2 1 1 2 -10 3 3 1 2 4 2 3 2 3 1 5 4 5 2 3 4 4 2 5 3 ...

  2. springcloud系列五 feign远程调用服务

    一:Feign简介 Feign 是一种声明式.模板化的 HTTP 客户端,在 Spring Cloud 中使用 Feign,可以做到使用 HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完 ...

  3. linux 环境下tomcat中部署jfinal项目

    tomcat中部署jfinal项目 问题现象如下图 问题描述: 我在自己的windows7系统上tomcat下面跑这个项目没有任何问题吗,但是当我把项目上传到linux服务器上的tomcatwebap ...

  4. 解决maven项目中有小红叉的问题

    首先在window--perferences--showview中显示problems中查看出错的原因

  5. Long类型比较不能直接用等于

    在判断两个Long型数据是否相等的时候遇到了一个问题. 使用“==”的疑问 if (user.getId() == admin.getId()) { return true; } else { ret ...

  6. html 一些坑。。。

    margin-left 和 margin-right 才能够使用 auto top 和 bottom 不可以 在网页设计中...通常给img 父容器 一个 宽度...同时 ,指定 img width= ...

  7. Luogu P5201 [USACO19JAN]Shortcut 最短路树???

    最短路树...开眼界了...之前想也没想过.... 先跑出来1到每个点最短路,然后建树时要标记点的入度,否则会多连边...然后深搜时更新新答案就是 #include<cstdio> #in ...

  8. 技巧:Python中print打印信息的同时打印文件、行号

    import sys def Log(msg): print('Print Message: '+msg+' ,File: "'+__file__+'", Line '+str(s ...

  9. python文件引用其他文件中的变量

    问题: 然后再另一个文件中引用该变量 报错:Cannot find reference 'User_Agent' in '__init__.py' less... (Ctrl+F1) 正确写法: fr ...

  10. python3与python2的区别 记录一波

    1.性能 Py3.0运行 pystone benchmark的速度比Py2.5慢30%.Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可 以取得很好的优化结果. Py3.1性能比Py2 ...