Handler引起的内存泄漏详解及解决方案
Posted 左大星
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler引起的内存泄漏详解及解决方案相关的知识,希望对你有一定的参考价值。
本文已在我的公众号CodeFire上优先发布,装载请注明出处.
在日常的开发中,我们经常遇到的异常里内存泄漏算是出现频率不低的一种,也常常是最令人崩溃的一种,当查询数据量比较大而调用数据库cursor没有关闭、在页面退出前某些注册了的事件没有取消、加载图片过大没做特殊处理的时候等等,这些都是造成OOM的原因。但是在我们最熟悉且最经常使用的Handler身上,也会“不经意间”给你一个惊喜。
让我们看一下下面再熟悉不过的代码:
当我无意中使用Lint检索代码时,看到如下提示:
这个时候我无意间想起当年我英语课上睡觉被罚站听讲的青春岁月,怎么突如其来了一种很庆幸的感觉...如果我没眼花,这句话是说Handler可能会引起内存泄漏。Why?
在Java中,非静态内部类和匿名内部类都会隐式持有当前类的外部引用。而在这里Handler是非静态内部类,所以此mHandler持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,当某个对象不需要再使用本该被回收时,而此时有另一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致这个本该被回收的对象因为不能被回收而停留在堆内存中,这个时候就发生了内存泄漏。
这个时候我们再换个方式:
在这里,我们用Handler发送了一个延迟消息。被延迟的消息会在被处理之前存在于主线程消息队列中3分钟,此时这个消息中包含了Handler的引用,我们所创建的Handler是一个匿名内部类实例,持有外部activity的引用,这个时候,你猜到了,这一系列操作将导致此Activity无法回收,进而会导致此Activity持有的资源都无法回收,最终造成内存泄漏。
(验证方法:反复打开此页面)
解决方法:
1. 使用静态内部类:
但是在开发过程中,我们使用handlemessag处理消息时,很多时候是需要使用外部类MainActivity的函数(更新UI等操作)。所以接下来有个更好的方式。
2. 使用弱引用解决静态内部类访问外部类
弱引用:可以被JVM顺利垃圾回收的一种引用方式。
创建一个静态的Handler内部类,然后对Handler持有的外部对象使用弱引用, 这样在回收时JVM可以销毁Handler持有的对象。但就算如此,在退出MainActivity后,Looper线程的消息队列中还是可能会有待处理的消息,因此建议在Activity销毁时,移除消息队列中的消息。
以上,使用静态类+弱引用可以避免Handler的内存泄漏。关注公众号,获取第一手业界信息和开发学习资源!
以上是关于Handler引起的内存泄漏详解及解决方案的主要内容,如果未能解决你的问题,请参考以下文章
Handler系列:Handler为什么会引起内存泄漏,怎么解决?
android中handler使用应该注意的问题(解决由handler引起的OOM内存泄漏)
Android性能优化之利用LeakCanary检测内存泄漏及解决办法(转)