内存泄漏指的是那些应该被回收的内存没有及时得到回收的现象。
内存泄漏的治理的目的就是要让这些应该被回收的对象被回收。
产生的根本原因往往是应该被回收的对象被某个静态对象或者长时间存在的对象(如线程)持有。
记录一下项目治理的内存泄漏问题。
使用leakcannary2
1、引入依赖
在leakcannary2中使用了定义一个contentProvider,而contentProvider的初始化是在Application前的,通过这个contentProvider实现了逻辑的注入,因此不用进行其他操作,引入依赖即可。
2、运行应用
在运行应用后,会leakcannary自动开始检测内存变化,此时我们可以多打开几个Activity,此时leakcannary就会在检测到activity.onDestroy()后开始检测内存泄漏的情况。
我们可以看到leakcannary设置的前台Service中弹出相关的提醒,同时桌面上会出现一个leakcannary的app。
进入leakcannary的app后,我们就可以看到相关的内存泄漏情况:
我们点击对应的提醒泄漏项目进去就可以看到相关的泄漏引用关系图,藉此就可以开始排查、解决内存泄漏问题。
内存问题分析解决:
1、xxxx.init()
原因分析
xxxx.init()在初始化时会将传入的context对象放到静态声明mObject当中,static对象是常驻在内存中的,因此不会进行回收,与其产生引用关系的context因此也不会被回收。
解决方法
将传入的context由activity的context换成APP中唯一的ApplicationContext。
2、MsgCenter持有消息
原因分析
MsgObserver持有所有的添加进去的回调监听,该类也是个静态类,因此不会被回收。会产生内存泄漏的问题。
解决方法
提供外部调用接口,在停止使用的时候把该回调去除。
一定要注意对于这个回调接口的调用处要做判空处理!
3、UpdataManager持有回调接口
原因分析
原因同2相似,还是因为静态类持有监听接口的原因。
解决方法
不使用的时候将该接口释放。这里要注意对接口进行判空处理,防止调用的时候出现空指针异常。
4、UserInfoManager持有回调接口
原因分析
同2点,还是持有了回调接口,没有及时释放的原因。
解决方法
不使用的时候将该接口释放。这里要注意对接口进行判空处理,防止调用的时候出现空指针异常。
5、PreferenceManager持有context实例
原因分析
静态实例持有外部活动引用,在活动应该释放时没有得到释放。
解决方法
应该在活动停止使用时将其释放,并且在使用实例的时候增加判空逻辑。
6、LogoReplaceManager回调问题
原因分析
同2,还是静态对象持有外部回调接口,没有及时释放导致的问题。
解决方法
在不使用的时候将其释放。
总结
1、在使用静态类的时候,要时刻注意引用关系的梳理,对于一些应该及时释放的资源,例如最经典的回调,要提供给外部接口释放的途径,避免长期持有导致内存泄漏问题。
2、对于使用传入Activity的情景,如果可以的话尽量采用传入applicationContext,避免传入活动实体造成的内存泄漏问题。
3、在给静态类的某个回调进行置空释放后,对其相关的回调调用处要进行判空处理,避免造成空指针异常。