上一篇简单介绍了OOM的原因和一些常见的OOM解决办法,这次给大家带来一些干货,运用AS-Memory Monitor分析和优化内存
Memory Monitor
Memory Monitor是AS自带的内存监视工具,可以实时显示程序内存消耗情况,并且提供了内存分析工具,帮助开发者程序中内存泄漏问题。如下图,蓝色代表分配的内存,灰色代表可以分配的。
Memory Monitor提供了三个强大的工具,下面我们通过这些工具来分析应用内存使用情况
Dump Java Heap
这个工具用于生成Java堆使用日志文件,里面包含了Java 对象在堆内存的占用情况,以及内存泄漏情况
1.点击如图按钮,AS将会生成日志文件
打开这个日志文件,有几块区域 我们来一块块分析
(1)Class Name: Java 堆中的类
里面有几个参数,Total Count:这个类的对象个数,Heap Count:分配的堆个数,Shallow Size 占用的内存大小,Retained Size:这个类的对象释放以后释放的空间大小。
下面是我的一些总结
byte[] ,大多数时候是因为缓存了图片引起的
FinalizerReference ,是因为某些引用无法GC,始终存在于内存中
(2)Instance
在这个窗口,我们可以看到对象实例,工具给出了对象占用的内存空间大小,以及对象的内容
(3)Reference Tree
这个我们可以看到对象的引用关系树,我们可以分析对象中的哪些变量占用的内存过大,从而优化代码。
(4)Analyzer Tasks
这是非常有用的一个日志,可以分析因为强引用无法销毁的对象,特别是Activity对象,在程序中为错误的使用Context,handler,都会造成内存泄漏,泄漏的地方在这里可以展示出来。
分析方法 (重点)
通过各种爬坑,我总结了以下方法,最快,最准的找到内存泄漏的地方。
step1:监控Memory Monitor内存情况,如果内存持续增高,可能发生泄漏,如果内存突然减少,可能发生GC。如果你在关闭一个Activity时,内存几乎没有减少,很可能这个activity就没有被回收。这时候我们点击Dump Java Heap。
step2:打开Analyzer Tasks窗口,勾选左上角你要分析的类型,点击绿色箭头按钮,生成日志,我们从上图可以看到有5个Activity对象没有回收,这些Activity就是我们要找的对象。
step3:点击一个Activity,我们看Reference Tree窗口
在这个窗口中,主要找两种变量,一个是Index,一个占用大的变量
Index是Activity中引用了这个Activity的对象,从上图中,我们1个个展开,我们可以看到是类AppManager中的变量mActivityStack中引用了这个Activity对象,并且没有在Activity销毁的时候释放这个引用。
我们通过可以找到占用大的变量,可以找到一些内存泄漏的根本原因,比如你的Activity有一个很大的bitmap对象,可能会导致系统的GC出现问题,无法回收。这些大变量我们要小心使用,比较严谨的方式就是在Activity 的onDestroy方法手动销毁。
step4:分析Class Name。通过前两步,我们可以基本解决因为引用问题导致Activity无法回收,但是OOM还有一个很大的原因就是图片导致的,我们查看Class Name,如果byte[]占用内存过大,就是图片缓存导致的,这个时候需要处理图片缓存了。处理的方法有很多,不同的图片加载库有不同的处理方法,推荐使用成熟的库,如glide,picasso ,fresco
Memory Monitor中还有一个按钮:Allocation Tracking,这个是分析应用线程占用资源的,也是一个非常棒的工具,生成的日志简单明了,我就不介绍了,有兴趣的同学可以试试。
总结
Memory Monitor可以很好的分析应用的内存问题,但是内存优化是一条漫漫长路,出现内存泄漏的情况有非常多,我们只要在不停的挖坑和爬坑中总结。后面我会继续介绍:内存泄露自动探测神器——LeakCanary 以及分析内存的强大助手MAT(memory Analyzer Tool)