内存优化(四):Mat大对象与泄露检测

2021-02-06  本文已影响0人  bug音音

使用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

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按钮,然后就出现下图:

image.png

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

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

image.png
生成的上述两个文件右键,点击Export to Standar .hprof导出到一个自己指定的目录文件夹
image.png
上图中Problem Suspect部分是代表可能存在内存泄漏的地方,Remainder表示正常的部分,再继续往下看
image.png image.png
上面就是对可能存在内存泄漏部分的代码的一个详细的信息,可以看到有些byte数组占用了大量的内存,keywords也是byte[],第二张图的DexCache可能占用的较多的内存,再点击
image.png
红色部分就会出现一些对象的信息列表:
image.png
可以输入正则表达式来筛选你想要的类,包名下所有的类,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
image.png
,点击with incoming references后
image.png
可以看到TaskExecutor对象被外部的两个对象所引用到了,并且可以看到引用的路径,右键TaskExecutor,选择Path to GC Roots或者或者Merge Shortest Paths to GC Roots选项,再选择exclude all phantom/weak/soft .ect references排除所有的弱引用,软引用对象寻找看有没有存在GC Roots,如果没有那就说明这个对象不存在内存泄漏,最终是会被GC回收,如果存在GC Roots
image.png
在继续查看GC Roots的对象是什么,其实就是被哪一个对象所引用了,上图可以查看到被外部的sendTaskExecutor对象所引用了而sendTaskExecutor是在ConnectionService这个常驻Service中的,所以理论上是不应该被回收的,所以这里不算是内存泄漏,假如sendTaskExecutor是一个Activity里面的字段,而此时Activity已经退出了,那么这时候就属于内存泄漏了,因为Activity退出后,Activity资源包括里面的对象应该是被回收掉的,那就找到对应的代码去具体分析可能造成内存泄漏的问题所在了,这里明确一点,存在GC Roots的不一定就一定存在内存泄漏,GC是不会回收GC Root或者被GC Root所引用的对象的,java对象内存泄漏其实就是对象在不用的时候仍然被其他对象持有引用导致GC无法回收

比较反复操作前的内存信息和反复操作后的内存信息分析前后有哪些不同

image.png

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

image.png

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

image.png

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

上一篇 下一篇

猜你喜欢

热点阅读