博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中使用Handler为何造成内存泄漏?
阅读量:6243 次
发布时间:2019-06-22

本文共 2759 字,大约阅读时间需要 9 分钟。

目录: 1.内存泄漏定义 2.Handler造成内存泄漏的原因 3.优化方案

1.内存泄漏定义

首先我们需要了解Java中的常见内存分配,包括静态存储区(方法区)、栈和堆等。

静态存储区:存储的是静态方法和全局的static数据和常量等,该区域的内存在程序编译时已经分配完成,在程序运行的整个过程都存在。 栈区:在执行方法时,方法体内的局部变量(包括基础数据类型和对象的引用等)都在栈上创建,在方法执行结束后,该区域局部变量所持有的内存会自动释放。栈内存分配运算内置于处理器的指令集中,效率高,但该区域的容量有限。 堆区:又称动态分配区,通常是存储new出来的对象的实例,该部分内存在没有引用时会由GC回收。

因此,我们通常说的内存泄漏是指:在堆区不断的创建对象,在该对象已经使用结束,不会再使用该对象时,但是还存在别的对象(生命周期较长)引用,导致该对象无法及时被GC回收,导致堆区可使用的内存越来越少,导致内存泄漏的产生,最终的后果就是OOM。其实Android中的内存泄漏的原因与Java中类似:生命周期较长的对象持有生命周期较短的对象的引用。

2.Handler造成内存泄漏的原因

在Android中的跨线程交互时,尤其是子线程与UI线程交互时,通过Handler在子线程中发送现象,Handler中做更新UI的操作,如下所示:

private Hand = new Handler(){       @Override       public void handleMessage(Message msg) {           super.handleMessage(msg);           switch (msg.what){               case UPDATE_UI:                   //更新UI操作                   break;           }       }   };复制代码

那么,通过Handler为何可以在子线程发送消息,在handleMessage中可以执行更新UI的操作?我们知道通常只有在主线程(通常指UI线程)可以执行更新UI的操作,因此最终还是调用UI线程更新。调用流程分析如下:

2.1 创建Handler对象

查看源码可以看到如下解释,当我们创建Handler对象时,就与该线程和该线程的消息队列相绑定,如果未与当前线程和线程队列绑定就无法正常执行事件的分发处理。我们在主线程创建Handler,因此就与主线程相绑定,Handler对象隐式的持有外部对象的引用,该外部对象通常是指Activity。

When you create a new Handler, it is bound to the thread / * message queue of the thread that is creating it

2.2消息队列处理

子线程执行处理结束后,通过Handler将消息发送处理,但如果此时当前界面已经销毁(Activity销毁),正常情况下,如果Activity不在使用,就可能被GC回收,但由于子线程仍未处理结束,仍持有Handler的引用(否则无法正常发送Handler消息),而该Handler持有外部Activty的引用,导致该Activity无法正常回收,导致内存的泄漏。 该引用的链如下: MessageQueue -> Message -> Handler -> Activity

3.优化方案

  1. Activity销毁时及时清理消息队列;
  2. 自定义静态Handler类+软引用。

3.1 Activity销毁时及时清理消息队列

在Activity销毁时,调用removeCallbacksAndMessages清除Message和Runnable。

mHandler.removeCallbacksAndMessages(null);复制代码
/* * Remove any pending posts of callbacks and sent messages whose     * obj is token.  If token is null,     * all callbacks and messages will be removed.     */    public final void removeCallbacksAndMessages(Object token) {        mQueue.removeCallbacksAndMessages(this, token);    }复制代码

3.2 自定义静态Handler类+弱引用

static class MyHandler extends Handler {        WeakReference
mWeakReference; private MyHandler(WeakReference
mWeakReference){ this.mWeakReference = mWeakReference; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(mWeakReference!=null){ Activity activity = mWeakReference.get(); if(activity!=null){ //handler消息处理 } } } }复制代码

由3.1的分析中可以看出,Handler造成内存泄漏的主要原因是持有当前Activty的强引用,造成Activity无法及时被回收,我们知道GC处理弱引用的机制为当对象销毁时,即使有弱引用存在,也会将其回收。

4.总结

避免使用Handler造成内存泄漏的方法如下:

  1. 在Activity的onDestory()方法中及时清理handler的消息队列;
  2. 自定义静态Handelr类,避免非静态内部类造成内存泄漏;
  3. 使用弱引用,使引用对象可以及时回收。

通过以上三种方式结合使用,可以有效的避免使用Handler不当,造成内存泄漏的情况。

转载地址:http://avvia.baihongyu.com/

你可能感兴趣的文章
tab选项卡前后有向前和向后按钮,点击实现上一个下一个
查看>>
iterm2远程ssh连接服务器乱码问题
查看>>
Spring singleton bean 与 prototype bean 的依赖
查看>>
MYSQL主从不同步延迟原理分析及解决方案
查看>>
使用LeakTracer检测android NDK C/C++代码中的memory leak
查看>>
软件即服务或将使本地Linux应用开发停速
查看>>
Python的学习笔记16------urllib
查看>>
深度剖析安卓Framebuffer设备驱动
查看>>
C/C++那些事儿之 数的转换
查看>>
用ViewPager实现欢迎引导页面
查看>>
ffmpeg源码分析 (三)
查看>>
Oracle11g x64使用Oracle SQL Developer报错:Unable to...
查看>>
概率论与数理统计14--方差
查看>>
关于PHP中按位取反问题
查看>>
scrapy爬取某网站,模拟登陆过程中遇到的那些坑
查看>>
设计师的知识管理
查看>>
Struts中ActionForm的作用
查看>>
昨天开始学习安卓
查看>>
centos 7 chrome安装
查看>>
为什么单个TCP连接很难占满带宽
查看>>