Android的Message Pool是个什么鬼,Message Pool会否引起OOM——源代码角度分析
引言
Android中,我们在线程之间通信传递通常採用Android的消息机制,而这机制传递的正是Message。
通常。我们使用Message.obtain()和Handler.obtainMessage()从Message Pool中获取Message。避免直接构造Message。
- 那么Android会否由于Message Pool缓存的Message对象而造成OOM呢?
对于这个问题,我能够明白的说APP***不会因Message Pool而OOM***。至于为什么,能够一步步往下看,心急的能够直接看最后一节——Message Pool怎样存放Message。
Obtain分析
    /**
     * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
     * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
     *  If you don't want that facility, just call Message.obtain() instead.
     */
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }
显然。Handler.obtain()是调用Message.obtain()来获取的。那么我门再来看下Message.obtain()源代码
    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
上述代码给我们透露几个个关键信息: 
1. 学过一点数据结构的。从上面的代码片基本就能判断出sPool是一个链表结构。另外sPool本身就是Message。 
2. 若链表sPool不为空,那么obtain()方法会从链表sPool头部取出一个Message对象赋值给m,并作为返回值返回。否则。直接new一个Message对象。
剧透下这里的sPool事实上就是Message Pool
Message Pool相关源代码分析
Message Pool数据结构
public final class Message implements Parcelable {
    // sometimes we store linked lists of these things
    /*package*/ Message next;
    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;
}看到关键信息了没?Message的成员有next、sPool和sPoolSize。这对于略微学过一点数据结构的,非常快就能判断出这是一个典型的链表结构的实现。sPool就是一个全局的消息池即链表。next记录链表中的下一个元素,sPoolSize记录链表长度。MAX_POOL_SIZE表示链表的最大长度为50。
Message Pool怎样存放Message
public final class Message implements Parcelable {
    private static boolean gCheckRecycle = true;
    /** @hide */
    public static void updateCheckRecycle(int targetSdkVersion) {
        if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
            gCheckRecycle = false;
        }
    }
    /**
     * Return a Message instance to the global pool.
     * <p>
     * You MUST NOT touch the Message after calling this function because it has
     * effectively been freed.  It is an error to recycle a message that is currently
     * enqueued or that is in the process of being delivered to a Handler.
     * </p>
     */
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }
    /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}从代码分析上看。消息池存放的核心方法就是上面的recycleUnchecked()方法:
- 将待回收的Message对象字段置空(避免因Message过大。使静态的消息池内存泄漏)。因此不管原先的Message对象有多大。终于被缓存进Message Pool前都被置空,那么这些缓存的Message对象所占内存大小对于一个app内存来说基本能够忽略。所以说。Message Pool并不会造成App的OOM。
- 以内置锁的方式(线程安全),判断当前线程池的大小是否小于50。若小于50,直接将Mesaage插入到消息池链表尾部;若大于等于50。则直接丢弃掉。那么这些被丢弃的Message将交由GC处理。
总结
- Message Pool是一个链表的数据结构。本身就是Message中的静态成员sPool(注。也是Message) 
- Message Pool不会由于缓存Message对象而造成OOM。 
Android的Message Pool是个什么鬼,Message Pool会否引起OOM——源代码角度分析的更多相关文章
- Android的Message Pool是什么——源码角度分析
		原文地址: http://blog.csdn.net/xplee0576/article/details/46875555 Android中,我们在线程之间通信传递通常采用Android的消息机制,而 ... 
- Android的消息处理机制,handler,message,looper(一)
		当应用程序启动时,Android首先会开启一个主线程(也就是UI线程),主线程为管理界面中的UI控件.在程序开发时,对于比较耗时的操作,通常会为其开辟一个单独的线程来执行,以尽可能减少用户的等待时间. ... 
- Android Studio gradle编译 NullPointerException(no error message)解决
		原文:Android Studio gradle编译 NullPointerException(no error message)解决 1.关闭Android Studio 2.找到工程目录下的 . ... 
- 异常:Message 850 not found; No message file for product=network, facility=NL解决方案
		一.异常信息: Message 850 not found; No message file for product=network, facility=NL 二.解决方案: 后来在 ... 
- 解决webApi<Message>An error has occurred.</Message>不能写多个Get方法的问题
		最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷. 本人最近在研究C#webAPI相关知识,发现webAPI不能够支持 ... 
- TNS-12560: Message 12560 not found; No message file for product=network, facility=TNS报错
		[oracle@localhost bin]$ ./lsnrctl startLSNRCTL for Linux: Version 12.2.0.1.0 - Production on 17-APR- ... 
- EXP-00000: Message 0 not found; No message file for product=RDBMS, facility=EXP问题的解决方案
		EXP-00000: Message 0 not found; No message file for product=RDBMS, facility=EXP 最近在服务器上准备做一个批处理,定时备份 ... 
- Message NNNN not found; No message file for product=network, facility=TNS
		Message NNNN not found; No message file for product=network, facility=TNS Table of Contents 1. 错误信息 ... 
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解(转)
		开始进入正题,我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃.相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟于心,即创建一 ... 
随机推荐
- myeclipse 改变模版
			一.修改Servlet的默认模板代码 使用MyEclipse创建Servlet时,根据默认的Servlet模板生成的Servlet代码如下: 1 package gacl.servlet.study; ... 
- Action的实现方式
			[Pojo方式] 1.概述 Pojo(Plain Ordinary Java Object)称为简单Java类,其实就是一个JavaBean. 2.示例 /** * Pojo类方式实现Action * ... 
- luogu3698 [CQOI2017]小Q的棋盘
			最长链是根节点到深度最深的结点的路径. 显然,要么直接走最长链,要么兜兜转转几个圈圈再走最长链,而最长链以外的结点因为要"兜圈",所以要经过两次. #include <ios ... 
- angularJs 中ui-router 路由向controller传递数据
			页面上 : ui-sref="home.dataAnalysis({role:'thirdpart:tokenverify',menuType:'a'})" 路由设置 .state ... 
- 大数据学习——azkaban工作流调度系统
			azkaban的安装部署 在/root/apps 1目录下新建azkaban文件夹 上传安装包到azkaban 2解压 .tar.gz 3删掉安装包 [root@mini1 azkaban]# .ta ... 
- Caffe 编译: undefined reference to imencode()
			本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/52150781 整理之前编译工程中遇到的 ... 
- OpenJ_Bailian——4115鸣人和佐助(带状态的A*)
			鸣人和佐助 Time Limit: 1000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u Submit Status Desc ... 
- SGU 275 To xor or not to xor【最大xor和 高斯消元】
			题目大意:给你n个数(n<=100)要你找出若干个数使他们的异或和最大 思路:高斯-若当消元消完以后削成若干个独立的行向量,将它们异或起来就好 #include<cstdio> #i ... 
- Uva5009 Error Curves
			已知n条二次曲线si(x) = ai*x^2 + bi*x + ci(ai ≥ 0),定义F(x) = max{si(x)},求出F(x)在[0,1000]上的最小值. 链接:传送门 分析:最大值最小 ... 
- 【单调队列】poj 2823 Sliding Window
			http://poj.org/problem?id=2823 [题意] 给定一个长度为n的序列,求长度为k的滑窗内的最大值和最小值 [思路] 裸的单调队列 注意用C++提交,不然会T,orz我用G++ ... 
