美文网首页
Handler究竟是如何泄漏内存的

Handler究竟是如何泄漏内存的

作者: 画十 | 来源:发表于2017-11-14 16:05 被阅读29次

常见有内存泄漏的写法

Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
                super.handleMessage(msg);
        }
};

解决方案

private final MyHandler handler = new MyHandler(this);
private static class MyHandler extends Handler {
        private final WeakReference<Activity> weakAcitivity;
        public MyHandler(Activity activity) {
                weakAcitivity = new WeakReference<Activity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
                final Activity activity = weakAcitivity.get();
                if (null != activity) {
                        // coding
                }
        }
  }

为什么会出现内存泄漏

注:以下均以在主线程new Handler()举例,在其他线程初始化Handler情况类似

跨进程原理概述

Handler跨线程原理是主线程中持有一个MessageQueue,在新线程中对这个队列进行插入(sendMessage()),然后在主线程循环读取然后通过调用callback,再调用handleMessage()实现跨线程的。

内存泄漏原理概述

因为很有可能会有好几个Handler同时向主线程MessageQueue 插入数据,而callback的时候需要回调到各自的Handler中去,所以插入MessageQueue中的实例Message会持有当前handler实例。而MessageQueue的生命周期是和当前主线程的生命周期一致的,如果Acitivity持有handler的话,那就必然会造成内存泄漏了。

源码分析
  1. 所有的sendMessage()最终都会调用下面代码

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                    RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue");
                    Log.w("Looper", e.getMessage(), e);
                    return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
    }
    
  2. 而在enqueueMessage()中,它会把this,也就是当前handler保存在msg中,然后插入到当前主线程的MessageQueue中。到此为止,真相大白。

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                    msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
    }
    
  3. 回调callback,在Looper.java中不断循环MessageQueue从中取出Message(只显示了部分关键代码)

    public static void loop() {
            for (;;) {
                    try {
                            msg.target.dispatchMessage(msg);
                            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
                    } finally {
                            if (traceTag != 0) {
                                    Trace.traceEnd(traceTag);
                            }
                    }
            }
    }
    
  4. 回到Handler中,看看被Looper调用的dispatchMessage()方法:

    public void dispatchMessage(Message msg) {
             if (msg.callback != null) {
                     handleCallback(msg);
             } else {
                     if (mCallback != null) {
                             if (mCallback.handleMessage(msg)) {
                                     return;
                             }
                     }
                     handleMessage(msg);
             }
    }
    
  5. 至此,真相得到了验证。

相关文章

  • java基础

    Handler怎样防止内存泄漏 handler引起内存泄漏的原因:由于handler的写法问题,如果handler...

  • 内存泄漏的场景及解决办法

    内存泄漏场景,以及开发过程如何避免内存泄漏。 判断 A引用B,A的生命周期长于B。 Handler导致内存泄漏:H...

  • Android的垃圾回收与内存泄露

    标签(空格分隔): Android 内存泄漏的基本知识请见博客一如何高效使用handler避免内存泄漏请见博客二 ...

  • Handler究竟是如何泄漏内存的

    常见有内存泄漏的写法 解决方案 为什么会出现内存泄漏 注:以下均以在主线程new Handler()举例,在其他线...

  • app性能优化 - 避免内存泄漏2

    提出问题: Handler造成的内存泄漏问题Handler之所以造成内存泄漏是因为在activity销毁的时候,H...

  • Handler内存泄漏的原因是什么?

    Handler内存泄漏的原因是什么? 这里提醒我们,这个handler必须时静态的,否则有可能会产生内存泄漏,所有...

  • 内存泄漏原理探讨

    当你如此定义一个handler的时候,系统会提示你,可以会产生内存泄漏,那么为什么会产品内存泄漏,如何避免。先来分...

  • Handler、Looper、message、MessageQu

    最近在写一篇内存泄漏的博客,还在完善中,其中写到handler引起的内存泄漏,发现对Handler了解太过狭隘,于...

  • Android 基础

    1、Android布局 2、Android内存泄漏总结 3 、Handler内存泄漏分析及解决 4...

  • Handler

    一,什么是handler 二,handler的使用 三,handler机制原理 四,handler引起的内存泄漏和...

网友评论

      本文标题:Handler究竟是如何泄漏内存的

      本文链接:https://www.haomeiwen.com/subject/aahfvxtx.html