引言

Android中,我们在线程之间通信传递通常採用Android的消息机制,而这机制传递的正是Message。

通常。我们使用Message.obtain()Handler.obtainMessage()从Message Pool中获取Message。避免直接构造Message。

  • 那么Android会否由于Message Pool缓存的Message对象而造成OOM呢?

对于这个问题,我能够明白的说APP***不会因Message Pool而OOM***。至于为什么,能够一步步往下看,心急的能够直接看最后一节——Message Pool怎样存放Message。

Obtain分析

Handler.obtainMessage()源代码

    /**
* 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()方法:

  1. 将待回收的Message对象字段置空(避免因Message过大。使静态的消息池内存泄漏)。因此不管原先的Message对象有多大。终于被缓存进Message Pool前都被置空,那么这些缓存的Message对象所占内存大小对于一个app内存来说基本能够忽略。所以说。Message Pool并不会造成App的OOM。

  2. 以内置锁的方式(线程安全),判断当前线程池的大小是否小于50。若小于50,直接将Mesaage插入到消息池链表尾部;若大于等于50。则直接丢弃掉。那么这些被丢弃的Message将交由GC处理。

总结

  • Message Pool是一个链表的数据结构。本身就是Message中的静态成员sPool(注。也是Message)

  • Message Pool不会由于缓存Message对象而造成OOM。

Android的Message Pool是个什么鬼,Message Pool会否引起OOM——源代码角度分析的更多相关文章

  1. Android的Message Pool是什么——源码角度分析

    原文地址: http://blog.csdn.net/xplee0576/article/details/46875555 Android中,我们在线程之间通信传递通常采用Android的消息机制,而 ...

  2. Android的消息处理机制,handler,message,looper(一)

    当应用程序启动时,Android首先会开启一个主线程(也就是UI线程),主线程为管理界面中的UI控件.在程序开发时,对于比较耗时的操作,通常会为其开辟一个单独的线程来执行,以尽可能减少用户的等待时间. ...

  3. Android Studio gradle编译 NullPointerException(no error message)解决

    原文:Android Studio gradle编译 NullPointerException(no error message)解决 1.关闭Android Studio  2.找到工程目录下的 . ...

  4. 异常:Message 850 not found; No message file for product=network, facility=NL解决方案

    一.异常信息:   Message 850 not found; No message file for product=network, facility=NL    二.解决方案:     后来在 ...

  5. 解决webApi<Message>An error has occurred.</Message>不能写多个Get方法的问题

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷.     本人最近在研究C#webAPI相关知识,发现webAPI不能够支持 ...

  6. 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- ...

  7. 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 最近在服务器上准备做一个批处理,定时备份 ...

  8. 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. 错误信息 ...

  9. Android异步消息处理机制完全解析,带你从源码的角度彻底理解(转)

    开始进入正题,我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃.相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟于心,即创建一 ...

随机推荐

  1. Java-构造一个字符串

    实用StringBuffer构造字符串 package com.tj; public class MyClass implements Cloneable { public static void m ...

  2. Java-克隆一个对象

    如可方便的克隆一个对象 package com.tj; public class MyClass implements Cloneable { public Object clone() { Clon ...

  3. 大数据学习——sql练习

    1. 现有如下的建表语句和数据: 建表语句 create table student(Sno int,Sname string,Sex string,Sage int,Sdept string)row ...

  4. hdu 2177 威佐夫博弈变形

    取(2堆)石子游戏 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  5. 九度oj 题目1051:数字阶梯求和

    题目描述: 给定a和n,计算a+aa+aaa+a...a(n个a)的和. 输入: 测试数据有多组,输入a,n(1<=a<=9,1<=n<=100). 输出: 对于每组输入,请输 ...

  6. 九度oj 题目1025:最大报销额

    题目描述:     现有一笔经费可以报销一定额度的发票.允许报销的发票类型包括买图书(A类).文具(B类).差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600 ...

  7. testng自定义html报告,根据freemaker生成

    [转] https://testerhome.com/topics/3487 [参考]https://www.cnblogs.com/cheese320/p/8890929.html  做了些修改,换 ...

  8. golang并发编程goroutine+channel(一)

    go语言的设计初衷除了在不影响程序性能的情况下减少复杂度,另一个目的是在当今互联网大量运算下,如何让程序的并发性能和代码可读性达到极致.go语言的并发关键词 "go" go dos ...

  9. SQL视图优化改写为存储过程遇到 双引号 单引号问题

    核心在于拼接SQL字符串中遇到中文双引号问题:   可以使用系统函数 替换掉set @pageStr =   replace(@queryStr,'"','''')  不过更推荐 使用两个单 ...

  10. 配置maven从私服上下载构件

    maven 本地setting.xml配置 <!--配置maven从私服上下载构件 --> <profiles> <profile> <repositorie ...