内存泄漏改进方案及代码修改

1. 内存泄漏类型

本次内存优化,发现如下内存泄漏类型:

  • Bitmap未即时释放

  • Handler泄漏

  • static成员泄漏

  • Callback泄漏

  • Activity leak window

  • cursor未关闭

内存泄漏问题详细描述,参见《内存优化评估文档》

下面将描述不同内存泄漏类型的解决方案。

 

2. 内存泄漏解决方案

2.1 Bitmap未即时释放

2.1.1泄漏原因

业务代码没有及时主动释放Bitmap,容易造成短时间内内存被大量占用,进一步诱发OOM的发生。

2.1.2解决方案

        解决方案思路有两种情况:

1) 对于从文件系统加载、Drawable资源加载,建立二级缓存管理该类Btimap;

 2) 对于内存创建、图形变换产生的Bitmap,由业务自己去即时释放资源。

     ImageUtisBitmapUtils封装了Bitmap加载/获取的二级缓存机制,加载文件系统的Bitmap,推荐使用ImageUtils中的getBitmap系列方法。

2.1.3实例

  • 调用ImageUtis获取Bitmap

1描述了使用二级缓存管理Bitmap

 

1使用二级缓存管理Bitmap

  • 自行管理Bitmap

2描述了自行管理Bitmap释放。

2自行管理Bitmap释放

2.2 Handler泄漏

2.2.1泄漏原因

Handler泄漏的原因,大多是匿名构建Handler实例,从而持有外部类Activity实例导致。

2.2.2解决方案

       解决方案思路有两种:

1)去除Handler实例持有的外部类引用,该类思路的做法,一般是将Handler的子类定义为静态内部类,或者以一个单独的类文件形式存在;

2)保证在Activity/Service退出时,清空消息队列中与Handler有关的所有消息。

      推荐使用第一种思路,实现起来简单、高效,第二种思路虽也可实现,但要考虑的面比较多,容易产生遗漏。

2.2.3实例

3描述了MyCellLayout.java文件中,有一个Handler泄漏实例。

3 Handler泄漏实例

4中所示代码对图3中的Handler泄漏做了修复。

43 Handler泄漏修复

2.3 static成员泄漏

2.3.1泄漏原因

Static类成员,其生命周期与App生命周期近乎等长,在不合理的设计中,static类成员持有的对象,其内部持有Activity实例等导致。

2.3.2解决方案

      解决方案思路有两种:

5)在static类成员持有的对象内部, 规避持有Activity实例;

6)避免使用static成员。

2.3.3实例

      图5描述了 GlobalMsgProcessHelper.javastatic类成员泄漏。

5 static类成员泄漏

      图6是对图5 static类成员泄漏的修复。

65 static类成员泄漏修复

2.3 Callback泄漏

2.4.1泄漏原因

Callback直接或间接持有Activity实例等导致。

2.4.2解决方案

解决方案思路,在Callback对象内部规避持有Activity实例。

2.4.3实例

      参见DeviceCategoryView.java DeviceCategoryDownloadCallback


2.5 Activity leak window

2.5.1泄漏原因

Activity异外先于Dialog退出,导致本异常抛出,本质也是一种内存泄漏。

2.5.2解决方案

构建BaseDialog,使所有自定义Dialog均扩展自此类,在BaseDialog内部实现在Activity退出前先行销毁的逻辑。

2.5.3实例

      图7描述了BaseDialog实现自释放逻辑。

      图8描述了CommonDialog派生自BaseDialog

7 BaseDialog实现自释放逻辑

8 CommonDialog派生自BaseDialog

2.6 cursor未关闭

2.6.1泄漏原因

Cursor使用完后等导致。

2.6.2解决方案

解决方案思路,在Cursor使用完后释放资源。

2.6.3实例

      图9描述了Cursor泄漏修复。

9 Cursor泄漏修复

 

 

 

 

 

转载于:https://www.cnblogs.com/tgltt/p/9554760.html