MAT内存泄露分析(一)

使用android shell命令查看内存使用情况

使用adb shell dumpsys meminfo pkgname或者直接使用AndroidStudio里面的memory usage功能然后就会出现如下信息:

Applications Memory Usage (kB):
Uptime: 14237237 Realtime: 23790474

** MEMINFO in pid 8071 [com.xtc.watch] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap        0        0        0        0    21924     8558     6405
  Dalvik Heap   122472   122372        0    15672   143308    65400    77908
 Dalvik Other    10361    10076      164      224
        Stack      440      440        0        8
    Other dev        4        0        4        0
     .so mmap     6441     3452     2636     2048
    .apk mmap      611        0      340        0
    .ttf mmap      538        0      504        0
    .dex mmap     8407     1640     2940       40
   Other mmap       80        4        0        0
      Unknown    10940    10936        0      148
        TOTAL   160294   148920     6588    18140   165232    73958    84313

 Objects
               Views:      288         ViewRootImpl:        2
         AppContexts:       11           Activities:        2
              Assets:        5        AssetManagers:        5
       Local Binders:       30        Proxy Binders:       38
    Death Recipients:        3
     OpenSSL Sockets:        1

 SQL
         MEMORY_USED:      138
  PAGECACHE_OVERFLOW:       24          MALLOC_SIZE:       62

 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       20            306       25/47/12  /data/data/com.xtc.watch/databases/upload.db
  • Native Heap是native层的内存堆栈,Dalvik Heap是java层的内存堆栈,如果这二者加起来的内存占用超过了应用最大内存限制就会报OOM异常,剩下的.so mmap是 C 库代码占用的内存,.jar mmap是Java 文件代码占用的内存 ,.apk mmap是apk代码占用的内存,.dex mmap是Dex 文件代码占用的内存
  • Objects中的Activities表示当前内存中的activity对象的个数,启动一个activity就会生成一个activity对象,当退出activity的时候,activity对象就会被释放,所以反复的进出一个activity界面然后查看Activities的个数有没有保持不变,如果增加了,那么就说明这个activity对象没有被释放,也就是说可能存在内存泄漏,但是具体哪里泄漏了并不知道

DDMS查看内存使用情况

eclipse中有一个ddms工具,可以查看线程信息(Threads),内存使用情况(VM Heap),内存分配跟踪(Allocation Tracker),CUP使用情况(Sysinfo CUP load),内存使用饼状图(Sysinfo Memory usage),这里我们暂时用到VM Heap,选择要查看的app进程,点击左上角的show heap updates,选择VM Heap并点击Cause GC按钮,然后就出现下图:


这里写图片描述
这里写图片描述

观察data object的Total Size选项,这个是app的创建的java对象做占用的内存大小,Count是总内存的对象的个数,反复的进出一个activity,看data object的Total Size有没有明显的增加,正常情况下进入一个activity的时候会明显增加,退出一个activity会有明显的回落,总体是维持在一个比较稳定的水平如果反复进出activity,Total Size不断上升,那么可能就存在内存泄漏了,需要具体排查

MAT分析内存泄漏,用AndroidStudio的Monitors的Memory

  • 多点击几下Initiate GC来回收一下可被释放的java对象,因为java的GC是定期有条件执行的,当内存中只存在很少的无用对象,这时候可能并不会触发GC,所以手动触发GC来保证开始检测内存的时候内存都是最干净的
  • 点击Dump Java Heap,然后过一会儿就会出现一份数据分析文件,这时候的这份数据文件是刚开始的程序对象内存占用情况,接下去就针对一个activity反复操作进出等等各种反复操作,觉得差不多了,这时候就再次疯狂点击Initiate GC回收一下可是放的对象,点击Dump Java Heap,这时候生成的数据分析文件就是经过你疯狂操作后的内存占用情况了


    这里写图片描述
    这里写图片描述

    生成的上述两个文件右键,点击Export to Standar .hprof导出到一个自己指定的目录文件夹

  • 去官网上面下载MAT来打开这两个文件开始内存分析


    这里写图片描述
    这里写图片描述

    上图中Problem Suspect部分是代表可能存在内存泄漏的地方,Remainder表示正常的部分,再继续往下看


    这里写图片描述
    这里写图片描述

    这里写图片描述
    这里写图片描述

    上面就是对可能存在内存泄漏部分的代码的一个详细的信息,可以看到有些byte数组占用了大量的内存,keywords也是byte[],第二张图的DexCache可能占用的较多的内存,再点击
    这里写图片描述
    这里写图片描述

    红色部分就会出现一些对象的信息列表:


    这里写图片描述
    这里写图片描述

    可以输入正则表达式来筛选你想要的类,包名下所有的类,Objects是对象的个数,Shallow Heap是当前对象所占用的内存大小,不包括对象内包含的对象的大小,Retained Heap表示当前对象包括对象内的子对象一共占用的内存大小,所以Retained Heap会比Shallow Heap大得多,对于一些我们已知的对象在内存不泄露的情况下,该对象的个数是确定的,所以可以通过分析Objects的个数来确定对象是否存在内存泄漏,例如同一个Activity对象在反复进出该Activity5次之后Objects的值为5,那就有问题了,说明同一个Activity创建了5个对象,正常情况下应该是退出Activity后,对象会被回收的,所以Objects的值应该是0才对,而有些对象的Objects不为0并不代表一定存在内存泄漏,例如ConnectionService是一个常驻的Service,那么它是不会被GC的,而ConnectionService里面的对象可不会被回收,所以这些对象的Objects值不为0其实就是正常的了,至于Shallow Heap和Retained Heap,我觉得可以用来分析一些对象的内存占用,Shallow Heap一般情况下不会很大,当你发现Retained Heap非常大的时候,那就说明该对象里面的对象可能占用了大量的内存,可能存在问题;在用Objects找到可能存在内存泄漏的对象后,右键List Objects,然后有两个选项:with outgoing references(表示的是当前对象,引用了外部引用)和with incoming references(表示的是当前查看的对象,被外部引用),一般当前对象泄漏了就是对象还被外部对象持有引用,无法被释放,所以我们选择查看with incoming references
    这里写图片描述
    这里写图片描述
    ,点击with incoming references后
    这里写图片描述
    这里写图片描述

    可以看到TaskExecutor对象被外部的两个对象所引用到了,并且可以看到引用的路径,右键TaskExecutor,选择Path to GC Roots或者或者Merge Shortest Paths to GC Roots选项,再选择exclude all phantom/weak/soft .ect references排除所有的弱引用,软引用对象寻找看有没有存在GC Roots,如果没有那就说明这个对象不存在内存泄漏,最终是会被GC回收,如果存在GC Roots
    这里写图片描述
    这里写图片描述

    在继续查看GC Roots的对象是什么,其实就是被哪一个对象所引用了,上图可以查看到被外部的sendTaskExecutor对象所引用了而sendTaskExecutor是在ConnectionService这个常驻Service中的,所以理论上是不应该被回收的,所以这里不算是内存泄漏,假如sendTaskExecutor是一个Activity里面的字段,而此时Activity已经退出了,那么这时候就属于内存泄漏了,因为Activity退出后,Activity资源包括里面的对象应该是被回收掉的,那就找到对应的代码去具体分析可能造成内存泄漏的问题所在了,这里明确一点,存在GC Roots的不一定就一定存在内存泄漏,GC是不会回收GC Root或者被GC Root所引用的对象的,java对象内存泄漏其实就是对象在不用的时候仍然被其他对象持有引用导致GC无法回收
  • 比较反复操作前的内存信息和反复操作后的内存信息分析前后有哪些不同
    这里写图片描述
    这里写图片描述

    ,点击红色部分后会出现下图


    这里写图片描述
    这里写图片描述

    可以看到对比后的Objects和Shallow Heap信息,看Objects表示前后两种内存信息对于同一个对象是否有个数上的增加,因为如果对象能被正常回收,那么开始操作前是0,操作后经过GC应该也是0,如果个数增加了,那就表示这个对象可能存在内存泄漏了,拖动到底部可看到总的比较情况
    这里写图片描述
    这里写图片描述

    上图可知,操作前的app的Objects总数比操作后的Objects少了1个,同时可以看到是HttpDns这个对象的问题,于是再切换到操作后的histogram去按照上述步骤查找GC Roots,再具体分析内存泄漏的问题

  • MAT当中还有一个dominator tree视图,具体就不复述了,可以参考这篇大神文章MAT内存分析

网上的开源项目LeakCanary也是分析内存泄漏的一种有效方法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容