`
bogongjie
  • 浏览: 230926 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

android Handler导致内存泄露分析

 
阅读更多
Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
            // do something.
    }
}

 当我们这样创建`Handler`的时候`Android Lint`会提示我们这样一个`warning: In Android, Handler classes should be static or leaks might occur.`。

 

一直以来没有仔细的去分析泄露的原因,先把主要原因列一下:    
- `Android`程序第一次创建的时候,默认会创建一个`Looper`对象,`Looper`去处理`Message Queue`中的每个`Message`,主线程的`Looper`存在整个应用程序的生命周期.
- `Hanlder`在主线程创建时会关联到`Looper`的`Message Queue`,`Message`添加到消息队列中的时候`Message(排队的Message)`会持有当前`Handler`引用,当`Looper`处理到当前消息的时候,会调用`Handler#handleMessage(Message)`.就是说在`Looper`处理这个`Message`之前,会有一条链`MessageQueue -> Message -> Handler -> Activity`,由于它的引用导致你的`Activity`被持有引用而无法被回收`
- **在java中,no-static的内部类会隐式的持有当前类的一个引用。static的内部类则没有。**

 

public class SampleActivity extends Activity {

  private final Handler mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                  // do something
                }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        // 发送一个10分钟后执行的一个消息
        mHandler.postDelayed(new Runnable() {
          @Override
          public void run() { }
        }, 600000);

        // 结束当前的Activity
        finish();
}

 

在`finish()`的时候,该`Message`还没有被处理,`Message`持有`Handler`,`Handler`持有`Activity`,这样会导致该`Activity`不会被回收,就发生了内存泄露.

 

解决方法 
- 通过程序逻辑来进行保护。
    - 如果`Handler`中执行的是耗时的操作,在关闭`Activity`的时候停掉你的后台线程。线程停掉了,就相当于切断了`Handler`和外部连接的线,`Activity`自然会在合适的时候被回收。 
    - 如果`Handler`是被`delay`的`Message`持有了引用,那么在`Activity`的`onDestroy()`方法要调用`Handler`的`remove*`方法,把消息对象从消息队列移除就行了。 
            - 关于`Handler.remove*`方法
                        - `removeCallbacks(Runnable r)` ——清除r匹配上的Message。    
                        - `removeC4allbacks(Runnable r, Object token)` ——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。
                        - `removeCallbacksAndMessages(Object token)` ——清除token匹配上的Message。
                        - `removeMessages(int what)` ——按what来匹配     
                        - `removeMessages(int what, Object object)` ——按what来匹配      
                        我们更多需要的是清除以该`Handler`为`target`的所有`Message(Callback)`就调用如下方法即可`handler.removeCallbacksAndMessages(null)`;
- 将`Handler`声明为静态类。
    静态类不持有外部类的对象,所以你的`Activity`可以随意被回收。但是不持有`Activity`的引用,如何去操作`Activity`中的一些对象? 这里要用到弱引用

public class MyActivity extends Activity {
        private MyHandler mHandler;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                mHandler = new MyHandler(this);
        }

        @Override
        protected void onDestroy() {
                // Remove all Runnable and Message.
                mHandler.removeCallbacksAndMessages(null);
                super.onDestroy();
        }

        static class MyHandler extends Handler {
                // WeakReference to the outer class's instance.
                private WeakReference<MyActivity> mOuter;

                public MyHandler(MyActivity activity) {
                        mOuter = new WeakReference<MyActivity>(activity);
                }

                @Override
                public void handleMessage(Message msg) {
                        MyActivity outer = mOuter.get();
                        if (outer != null) {
                                // Do something with outer as your wish.
                        }
                }
        }
}

 

本文为转载,看源处请移步:

http://www.eoeandroid.com/thread-332265-1-1.html

分享到:
评论

相关推荐

    解决Android使用Handler造成内存泄露问题

    内存泄露的危害就是会使虚拟机占用内存过高,导致OOM(内存溢出),程序出错。接下来通过本文给大家分享Android使用Handler造成内存泄露问题及解决方法,一起看看吧

    android内存泄露:4、Toast的错误使用导致内存泄露

    详细可参考博文:原创 android内存泄露:3、Handler的错误使用导致内存泄露 ,这篇文章我们将介绍:Toast的错误使用导致内存泄露 二、Toast的错误使用导致内存泄露 我们通常,连续点击按钮多次提示的 Toast,它...

    Handler对象中使用匿名内部类或非静态内部类正确地释放消息避免内存泄漏或增加Native内存

    当我们在Handler对象中使用匿名内部类或非静态内部类时,如果没有正确地释放消息,就可能会导致内存泄漏或增加Native内存。 解决这个问题的方法有两种: 减少notifyItemChanged的调用次数,尽量在数据变化后一次性...

    Android 优化Handler防止内存泄露

     1 关于常见的Handler的用法但是可能导致内存泄露   2 优化方式请参考BetterHandler和BetterRunnable的实现 package cc.cc; import java.lang.ref.WeakReference; import android.os.Bundle; import android....

    浅谈Android应用的内存优化及Handler的内存泄漏问题

    在程序运行中会创建对象,如果未合理管理内存,比如不及时回收无效空间就会造成内存泄露,严重的话可能导致使用内存超过系统分配内存,即内存溢出OOM,导致程序卡顿甚至直接退出。 内存泄露(Memory Le

    Android中Handler引起的内存泄露问题解决办法

    主要介绍了Android中Handler引起的内存泄露问题解决办法,本文讲解了导致内存泄露的情景,并给出了修改后的代码,需要的朋友可以参考下

    Android 中Handler引起的内存泄露

    在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用。通常我们的代码会这样实现...但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告 In Android, Handler c

    详解Android内存泄漏检测与MAT使用

    虽然JVM提供了自动垃圾回收机制,但是还是有很多情况会导致内存泄漏。 内存泄漏主要原因就是一个生命周期长的对象,持有了一个生命周期短的对象的引用。这样,会导致短的对象在该回收时候无法被回收。Android中...

    uncleShi#AndroidFace#Android部分-5 Handler1

    1.子线程一定不能更新UI吗 2.给我说说Handler的原理 3.Handler导致的内存泄露你是如何解决的 4.如何使用Handler让子线程和子线程通信

    Android内存溢出及内存泄漏原因进解析

    当内存泄漏过多时,可用内存空间会减少,应用程序申请的内存不够用,就会导致内存溢出。 内存溢出原因: 1.内存泄漏过多。 2.内存中加载的数据量超过内存的可用量。 3.集合类(用于存储对象的引用)中有对对象的引用...

    Android中的内存泄漏

    什么是内存泄漏 长生命周期的对象持有了短生命周期的对象,从而导致短生命周期的对象不能被释放 垃圾回收机制 垃圾回收机制分为:引用计数法、可达性分析法 引用计数法(有循环引用的问题):Python、Object-C、Swift ...

    5个Android开发中比较常见的内存泄漏问题及解决办法

    android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了。 内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统分配的内存...

    Android中内存泄漏需要的注意点

    如果你对垃圾回收机制有所了解,我想这个问题基本难不住你,因为知道了原理,自然不会去触碰这些极易导致内存泄漏的雷区。 该题重在积累,不需要死记硬背,自己多总结即可。 1. 长生命周期对象持有 Activity 这基本...

    Kotlin中的handler如何避免内存泄漏详解

    前言: 哲学老师说,看待事物无非是了解它是什么,为什么,怎么做 所以,首先,我们先了解一下什么是“内存泄漏” 摘自百度的一段话:用动态存储分配函数动态...Handler在Android开发中经常使用,一不小心就会陷入

    Android常见的几种内存泄漏小结

    一、背景 ...由于Android系统为每个应用程序分配的内存有限,当一个应用中产生的内存泄漏比较多时,就难免会导致应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash。了

    Android性能优化之利用强大的LeakCanary检测内存泄漏及解决办法

    前言: 最近公司C轮融资成功了,...如果在对象的生命周期本该结束的时候,这个对象还被一系列的引用,这就会导致内存泄漏。随着泄漏的累积,app将消耗完内存。 内存泄漏造成什么影响? 它是造成应用程序OOM的主要原

    Android内存泄漏的轻松解决方法

    严重的时候可能会导致内存溢出错误,即 OOM Error 下面我们从基础说起 基础知识 Java 的内存分配简述 方法区(non-heap):编译时就分配好,在程序整个运行期间都存在。它主要存放静态数据和常量; 栈区:当...

    CountDownTimer

    1、 使用线程和Handler的方式,定时刷新倒计时数字,这种方式容易导致内存泄露,所以一般都使用弱引用,控制数字的刷新。 2、 自定义倒计时按钮 3、 使用Android提供的CountDownTimer结合TextView实现倒计时功能

    Android自定义短信倒计时view流程分析

    为了保证activity销毁的同时倒计时线程依然进行同时重新创建销毁又不会导致内存泄漏,我使用了handler的弱引用将handler和runnable设置成静态,同时通过一系列变量来销毁关闭线程保存状态,话不多说先看效果图: ...

    谈一谈Android内存泄漏问题

    内存泄漏:是指内存得不到GC的及时回收,从而造成内存占用过多,从而导致程序Crash,也就是常说的OOM。 一、static 先来看下面一段代码 public class DBHelper { private static DBHelper db= null; private ...

Global site tag (gtag.js) - Google Analytics