Android 内存检测工具介绍

1.内存抖动

短时间内有大量对象创建销毁,它伴随着频繁的GC,比较典型的就是字符串拼接造成的内存抖动

示例.png

内存抖动会产生很多的内存碎片,造成内存不连续,在申请内存的时候就有可能造成OOM

CMS垃圾回收器老年代标记-清除算法:内存碎片.png

android内存检测工具有androidStudio自带的Memory Profiler和mat,我们先看Memory Profiler
,这个工具官网介绍的十分详细https://developer.android.google.cn/studio/profile/memory-profiler,这里我会介绍这个工具的具体使用,
要打开 Memory Profiler,请按以下步骤操作:

  1. 依次点击 View > Tool Windows > Profiler(您也可以点击工具栏中的 Profile 图标

    image

    )。

  2. 从 Android Profiler 工具栏中选择要分析的设备和应用进程。如果您已通过 USB 连接设备但系统未列出该设备,请确保您已启用 USB 调试。

  3. 点击 MEMORY 时间轴上的任意位置以打开 Memory Profiler。

    截屏2020-11-04 下午2.09.11.png

    这是我的一个实例代码,我们在分析的时候一定要点击用于强制执行垃圾回收事件的按钮。
    我们是可以看到这是一个斜坡,说明内存是逐渐增大,这时我们的并没有启动新的页面,当然我们不能只用眼睛去看,还要看具体的数据,
    截屏2020-11-04 下午2.14.26.png

    这里的Total是47.4M
    截屏2020-11-04 下午2.14.39.png

    这时就变成了47.6M,说明内存的确在逐渐变大,这时没有出现锯齿是因为内存没有达到需要GC的点,但这时并不能代表它没有内存抖动。
    这时候我们截取一段进行观察
    截屏7.png

    我们可以在右下角可以看到onDraw方法里面的126行
    截屏08.png

    可以看到我们在自定义View里面的onDraw方法里面进行创建对象,我们知道onDraw方法会很有可能多次调用的,
    同样我们发现了同样的问题
    截屏24.png

    84行找到是Paint在onDraw里面进行创建
    截屏56.png

    我们再来看一下91行
    截屏07.png

    截屏58.png

    还有一个String的问题
    截屏42.png

    上面就是我们用profile找到的一些问题,现在我们进行修改一下上面的问题。
    把path和paint提取到外面,colors是个数组,使用属性动画去改变
    截屏06.png

    截屏22.png

    现在我们重新使用profile检测一下
    截屏.png

    emm,至此,memory profile工具的使用就先介绍到这里。

  • 预防抖动
    避免在循环中创建对象
    避免在频繁调用的方法中创建对象,如View的onDraw方法
    允许复用的情况下,使用对象池进行缓存,如Handler的Message单链表(obtain)
2.内存泄漏

程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费。
长生命周期对象持有短生命周期对象的强引用,从而导致短生命周期对象无法被回收。

  • 可达性分析法

    通过一系列称为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索所有的引用链,当一个对象到GC Roots没有任何引用链(即GC Roots到对象不可达)时,则证明此对象是不可用的
    GCRoots.png

    截屏.png

    第二种解决方法


    截屏.png

    下面介绍如何使用mat进行检测
    截屏.png

我们在使用profile工具后,点击Dump Java heap按钮会生成一个dump文件,我们把这个文件导出到本地某个文件夹,使用命令进行转换
hprof-conv xxx.hprof converted-dump.hprof,然后新生成的文件就是hprof


截屏.png

然后我们打开mat工具,导入hprof文件


截屏.png

Histogram列出所有的对象
我们点击Histogram,然后选择Group by package这样我们就可以找出我们的类
截屏2020-11-04 下午6.05.47.png

截屏2020-11-04 下午6.06.56.png

然后我们排除软弱虚引用看看还有哪些引用

截屏2020-11-04 下午6.10.09.png

这时我们可以看到context就是secondActivity被IOSStyleLoadingView所持有,这样就没办法进行回收,我们可以看一下代码找一下原因和解决办法


截屏2020-11-04 下午6.12.09.png

addUpdateListener默认持有对外部类的强引用
解决办法


截屏2020-11-04 下午6.12.19.png

现在我们再来试下,看看问题有没有解决
我们重新生成hprof文件并打开
截屏2020-11-04 下午6.20.53.png

截屏2020-11-04 下午6.21.01.png

可以看到没有强引用了,说明问题已经解决了。

内存问题常见场景

集合类
当使用集合时,只有添加元素,没有对应的删除元素,如EventBus只有注册没有注销
静态成员/单例
作为GC ROOT,持有短生命周期引用(如Activity)导致其短生命周期对象无法释放。
未关闭/释放资源
如FileOutputStream未close,一定要在finally里面close
非静态内部类
如Handler postDelayed一个匿名Runnable,退出Activity时消息没处理完

你可能感兴趣的:(Android 内存检测工具介绍)