Android内存泄漏分析

作者: 码上述Andy | 来源:发表于2019-07-01 23:26 被阅读18次

    1 .工具介绍

    1.1使用Android Studio查看内存快照:

    (1)可以查看对象对应的文件目录及内容,比如Bitmap可以看到对应的图片。
    (2)可在InstanceView区右击可快速jump to source。
    (3)不方便查看对象的最短引用链。


    image.png

    如图分为Heap Dump,Instance View, References三个区域。
    其中Heap Dump区域:
    Arrange by class:按照类进行分组
    Arrange by package:按照包进行分组
    Arrange by callstack:按照调用堆栈进行分组
    说明:
    Total Count 该类的实例总数
    Sizeof 单个实例所占空间大小
    Shallow Size 堆里所有实例大小总和(Heap Count * Sizeof)
    Retained Size 该类所有实例所支配的内存大小
    Heap Count 所选择的堆中该类的实例的数量
    Depth GC根节点到所选实例的最短路径的深度

    2.1使用MAT查看内存快照(推荐用):

    (1)可以方便查看对象的对象的最短引用链。
    (2)不方便定位对象对应的资源。

    点击Histogram可显示内存快照文件


    image.png

    建议两个工具配合一起使用。

    2.内存信息

    通过adb查看当前进程的内存信息:

    adb shell dumpsys meminfo <包名>
    

    以我们产品为例:

    adb shell dumpsys meminfo com.baidu.launcher      
    * daemon not running; starting now at tcp:5037
    * daemon started successfully
    Applications Memory Usage (in Kilobytes):
    Uptime: 81529000 Realtime: 81529000
    
    ** MEMINFO in pid 11898 [com.baidu.launcher] **
                       Pss  Private  Private  SwapPss     Heap     Heap     Heap
                     Total    Dirty    Clean    Dirty     Size    Alloc     Free
                    ------   ------   ------   ------   ------   ------   ------
      Native Heap     9685     9660        0      127    11520     9884     1635
      Dalvik Heap     5341     5296       16       39     6069     3051     3018
     Dalvik Other     3284     3284        0       36                           
            Stack       64       64        0        0                           
           Ashmem       23        0        0        0                           
        Other dev        8        0        8        0                           
         .so mmap    11878      420     8212       20                           
        .apk mmap     1039        0       80        0                           
        .dex mmap    22381        4    11124        4                           
        .oat mmap      835        0      156        0                           
        .art mmap     3184     2628       56      345                           
       Other mmap       39        0        0        4                           
       EGL mtrack     5226     5226        0        0                           
        GL mtrack     8963     8963        0        0                           
          Unknown     2490     2488        0      132                           
            TOTAL    75147    38033    19652      707    17589    12935     4653
     
     App Summary
                           Pss(KB)
                            ------
               Java Heap:     7980
             Native Heap:     9660
                    Code:    19996
                   Stack:       64
                Graphics:    14189
           Private Other:     5796
                  System:    17462
     
                   TOTAL:    75147       TOTAL SWAP PSS:      707
     
     Objects
                   Views:       33         ViewRootImpl:        1
             AppContexts:        4           Activities:        0
                  Assets:        4        AssetManagers:        2
           Local Binders:       41        Proxy Binders:       29
           Parcel memory:       22         Parcel count:       87
        Death Recipients:        1      OpenSSL Sockets:        4
                WebViews:        0
     
     SQL
             MEMORY_USED:      287
      PAGECACHE_OVERFLOW:      179          MALLOC_SIZE:      117
     
     DATABASES
          pgsz     dbsz   Lookaside(b)          cache  Dbname
             4      200                   2839/252/25  /data/user/0/com.baidu.launcher/databases/puffer.db
             4       20                        0/15/1  /data/user/0/com.baidu.launcher/databases/crabstat.db
             4       56                        3/35/5  /data/user/0/com.baidu.launcher/databases/duershow.db
             4       12                         0/0/0    (attached) temp
    

    3.内存快照获取三种方式

    3.1 通过android studio ----Memory Profiler
    3.2 打开monitor(/Users/zhouwen/Library/Android/sdk/tools/monitor)


    image.png

    选取自己的应用进程名-->点击dump HPROF file按钮即可生成hprof文件。
    3.3 通过adb shell am dumpheap也可以dump出hprof文件。

    adb shell 
    cd data/local/tmp
    am dumpheap <包名> output.hprof
    
    ➜  ~ adb shell
    tb8765ap1_bsp_1g:/ # cd data/local/tmp
    tb8765ap1_bsp_1g:/data/local/tmp # am dumpheap com.baidu.launcher output.hprof
    

    4.内存泄露分析

    4.1MAT(Memory Analyzer Tool)以我们项目为例:

    4.1.1 内存快照获取

    普遍的方式通过monitor dump对应的内存快照或者通过adb shell进入data/local/tmp目录下 am dumpheap 出对应应用的hprof文件。以我们项目为例,我们则通过跑稳定性当内存飙升到大于60M以上,会自动adb去dump一份内存快照上传到后台。

    4.1.2 内存快照转换

    /Users/zhouwen/Library/Android/sdk/hprof-conv input.hprof  output.hprof
    

    通过以上转换成mat可以解析的文件。

    4.1.3 占比

    image.png

    以上三个可能出现泄露问题的占比分布。

    4.1.4 内存可能泄露的点

    image.png
    image.png

    如上图所示byte[]数组,Bitmap,NewBgView可能出现泄露。

    4.1.5 通过搜索关键字可以搜索到相关泄露对象,比如Bitmap,Activity等。

    image.png
    image.png

    我自己一般分析内存步骤如下:

    第一步:点击historgram按钮


    image.png

    通过Objects(对象数量)可以看出AlarmHomeCard和BaseCard对象数量比较多,可能存在泄露。
    第二步:右击Objects数量比较多的class Name-->Merge Shortest Paths To Gc Roots-->exclude weak/soft references然后一个一个点开引用链分析。
    以下是HomeCardGroup的第六个匿名内部类实例被handler引用着导致释放不了,对应NewBgView这个泄露点。


    image.png
    以下是TimerHomeCard的第一个匿名内部类实例被handler引用导致界面退出释放不了。
    image.png

    通过以上分析结合代码逻辑去看看到底是那个地方出现了内存泄露。

    泄露原因及优化

    原因:
    上面两个内存泄露案例都有因为匿名内部类默认引用外部类,当界面关闭,导致当前界面一直释放不了,内存泄露。
    解决办法:
    将匿名内部类改成static,使其对外部类没有引用。

    4.1.6参数说明

    Objects:对象数量
    Shallow Size:堆里所有实例大小总和(Heap Count * Sizeof)
    Retained Size:该类所有实例所支配的内存大小
    List objects:
    with outgoing references: 列出这个对象被哪些对象引用
    with ingoing references:列出这个对象持有哪些对象引用
    Merge Shorts Path To GC Roots:
    with all references:所有的引用。
    exclude weak references: 去除弱引用。
    exclude weak/soft references:去除弱/软引用(用的最多)。
    其他就不列举了。

    4.2 android studio分析(直接把内存快照拖至到as里)

    这里就不介绍了,分析起来没Mat工具方便。

    5.常见的内存泄露地方

    5.1.Handler内存泄露,最好使用弱引用,释放时清除对应消息。
    5.2.Cursor,File等使用完未关闭,及时关闭以便缓存数据及时回收。
    5.3.过多的WebView,一个应用使用一个WebView并且最好放到单独的进程中。
    5.4.注册对象未注销掉,导致界面一直释放不了。
    5.5.及时释放容器对象。
    5.6.匿名内部类持有外部引用。
    5.7.单例中的Context生命周期大于本身Context生命周期

    相关文章

      网友评论

        本文标题:Android内存泄漏分析

        本文链接:https://www.haomeiwen.com/subject/bjvaqctx.html