Android 内存检测工具介绍
1.内存抖动
短时间内有大量对象创建销毁,它伴随着频繁的GC,比较典型的就是字符串拼接造成的内存抖动
示例.png内存抖动会产生很多的内存碎片,造成内存不连续,在申请内存的时候就有可能造成OOM
android内存检测工具有androidStudio自带的Memory Profiler和mat,我们先看Memory Profiler
,这个工具官网介绍的十分详细https://developer.android.google.cn/studio/profile/memory-profiler,这里我会介绍这个工具的具体使用,
要打开 Memory Profiler,请按以下步骤操作:
-
依次点击 View > Tool Windows > Profiler(您也可以点击工具栏中的 Profile 图标
image)。
-
从 Android Profiler 工具栏中选择要分析的设备和应用进程。如果您已通过 USB 连接设备但系统未列出该设备,请确保您已启用 USB 调试。
-
点击 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时消息没处理完