一次内存泄漏导致的OOM实例分析和解决

来源:互联网 发布:生化危机剧情 知乎 编辑:程序博客网 时间:2024/05/18 03:17

一: 问题描述

   在B公司项目中的一个界面,ViewPager展示20多张照片,进行一些操作比如:左右滑动照片,点击编辑问题,退出问题详情再进去等,会导致问题详情的照片ViewPager部分照片显示不出,甚至直接OOM崩溃。

 

二:解决方法

   通过Log查看,发现确实是OOM,导致APP崩溃。(只不过ImageLoader框架作了简单Cash 以至于有时不会崩溃,只是加载不出图片)    


第一步,获取设备的heapSzie,如下:


 

ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
int heapSize = manager.getMemoryClass();
int maxHeapSize = manager.getLargeMemoryClass();  // manafest.xml   android:largeHeap="true"

 

   heapSize是设备分配给app的最大堆内存   maxHeapSize 是当配置了android:largeHeap="true" 才有的最大堆内存,一般是heapSize的2-3倍

以HTC ONE为例,两个值分别是: 192M和512M,之前这个OOM解决办法是设置 大堆内存,才避免了OOM,现在关闭这个设置,那就是192M为上限


第二步,尝试复现问题 ,造成OOM无非两个原因  要么是加载较大资源一般是图片,直接导致内存超过了heapSize, 要么是某些Activity(Fragment)有内存泄漏,多次创建没有回收导致超过heapSize。在本例中,因为加载图片用的ImageLoader这个成熟框架,并且在详情界面加载30张图片来回滑动也没有OOM,heapSize一直稳定在120M左右。所以考虑是内存泄漏,尝试点击编辑问题并且返回,然后退出问题详情界面  多次操作,复现了该问题:

  内存上升到171M不再下降,并且此时照片已经加载不出来了,显示默认图。


   第三步,用AndroidStudio自带的内存分析工具分析,点击Dump Java Heap:

会在代码区  生成当前时间点的 .hprof格式文件,里面当前的每个对象 内存占用情况,我们现在怀疑ViewDefectPhotoActivity 可能内存泄漏  看一下:ViewDefectPhotoActivity 确实占用了很高的内存  而且有8个实例化对象,足以证明它有内存泄漏,随便点击其中一个,发现都和EditDefectActivity的内部类 ShowEditDefectHelper有关。而且ShowEditDefectHelpe前面带有 黄蓝三角树 这个图标表示,他可以被GC访问到,也就是无法回收


          接下来看看ShowEditDefectHelper这个对象持有什么引用,右键点击 Go To Instance:

 

       发现这个内部类也被实例化多次,即使不在编辑界面 ,他也没有被回收。随便点击一个,发现属于EventBus的引用  ,并且EventBus带有黄蓝图标,那么问题就大概找到了,因为EventBus一直持有这个内部类的引用,导致这个内部类无法被回收,而这个内部类持有ViewDefectPhotoActivity引用,导致ViewDefectPhotoActivity无法被回收  这个界面有很多图片资源  当实例化7,8次之后  出现了OOM。

     看下是不是EventBus是不是没有解绑定,在ShowEditDefecthelper中:

 

    红框是旧代码,这一句是个低级错误   this指向了CancelResult.AsyncCancelCallback这个匿名内部类,导致ShowEditDefecthelper注册的EvnetBus无法被解绑定!所以问题正确复现方式是,在问题详情界面加载很多图片,然后点击编辑问题马上取消,不要跳到编辑界面,多次操作就OOM。当问题照片很多的时候,获取编辑问题需要时间,就有了取消的机会,这也就造成是照片过多加载导致OOM的错像!

     改成上图这句注释代码,问题解决!类似的还有广播注册等等,一定要注意确保正确的解除绑定!

1 0
原创粉丝点击