原文地址:

http://blog.csdn.net/xplee0576/article/details/46875555

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

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

  • 那么Android会否因为Message Pool缓存的Message对象而造成OOM呢?对于这个问题,我可以明确的说APP不会因Message Pool而OOM。至于为什么,可以一步步往下看,心急的可以直接看最后一节——Message Pool如何存放Message。

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();
}

从代码片中,可以看到Message是直接由sPool赋值的。

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 Pool相关源码分析

Message Pool数据结构

    // 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; private static boolean gCheckRecycle = true;

从代码中可以很明确的看到,Message Pool的数据结构实际就是一个链表。sPool就是一个全局的消息池,sPoolSize记录链表长度,MAX_POOL_SIZE表示链表的最大长度为50。

Message Pool如何存放Message

    /** @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处理。

Android的Message Pool是什么——源码角度分析的更多相关文章

  1. 源码角度分析-newFixedThreadPool线程池导致的内存飙升问题

    前言 使用无界队列的线程池会导致内存飙升吗?面试官经常会问这个问题,本文将基于源码,去分析newFixedThreadPool线程池导致的内存飙升问题,希望能加深大家的理解. (想自学习编程的小伙伴请 ...

  2. Android进阶:二、从源码角度看透 HandlerThread 和 IntentService 本质

    上篇文章我们讲日志的存储策略的时候用到了HandlerThread,它适合处理"多而小的任务"的耗时任务的时候,避免产生太多线程影响性能,那这个HandlerThread的原理到底 ...

  3. 【原创】源码角度分析Android的消息机制系列(五)——Looper的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. Looper在Android的消息机制中就是用来进行消息循环的.它会不停地循环,去MessageQueue中查看是否有新消息,如果有消息就立刻 ...

  4. 【原创】源码角度分析Android的消息机制系列(三)——ThreadLocal的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 先看Android源码(API24)中对ThreadLocal的定义: public class ThreadLocal<T> 即 ...

  5. 【原创】源码角度分析Android的消息机制系列(六)——Handler的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 先看Handler的定义: /** * A Handler allows you to send and process {@link Mes ...

  6. 【原创】源码角度分析Android的消息机制系列(四)——MessageQueue的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. MessageQueue,主要包含2个操作:插入和读取.读取操作会伴随着删除操作,插入和读取对应的方法分别为enqueueMessage和ne ...

  7. Android的开机流程及对应源码位置分析

    1.系统引导bootloader 1)源码:bootable/bootloader/* 2)说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a)开机按Camera+Power启动 ...

  8. Android的Message Pool是个什么鬼,Message Pool会否引起OOM——源代码角度分析

    引言 Android中,我们在线程之间通信传递通常採用Android的消息机制,而这机制传递的正是Message. 通常.我们使用Message.obtain()和Handler.obtainMess ...

  9. Adroid学习之 从源码角度分析-禁止使用回退按钮方案

    有时候,不能让用户进行回退操作,如何处理? 查看返回键触发了哪些方法.在打开程序后把这个方法禁止了. 问题:程序在后台驻留,这样就会出现,其他时候也不能使用回退按钮.如何处理,在onpase()时方法 ...

随机推荐

  1. Android探索之ContentProvider熟悉而又陌生的组件

    前言: 总结这篇文章之前我们先来回顾一下Android Sqlite数据库,参考文章:http://www.cnblogs.com/whoislcj/p/5506294.html,Android程序内 ...

  2. ASP.NET Core的配置(3): 将配置绑定为对象[上篇]

    出于编程上的便利,我们通常不会直接利用ConfigurationBuilder创建的Configuration对象读取某个单一配置项的值,而是倾向于将一组相关的配置绑定为一个对象,我们将后者称为Opt ...

  3. 跟我学Angular2(1-初体验)

    0.导言 Angular1作为最流行的前端MV*框架,给前端开发带来了极大的便利性.但是,仍然有许多不好的地方已经很难再改变了.Angular团队根据WEB发展的趋势和Angular1中积累的经验来开 ...

  4. 使用CSS3 Media Queries实现网页自适应

    原文来源:http://webdesignerwall.com 翻译:http://xinyo.org 当今银屏分辨率从 320px (iPhone)到 2560px (大屏显示器)或者更大.人们也不 ...

  5. Android随笔之——模拟按键操作的几种方式

    前几天转过一篇Android上模拟按键操作.触屏事件的博客,昨天又去找了百度.谷歌了一下,写了一点简单的测试代码,留待不时之需.有需要看之前转载的那篇博客的请看这里→_→转:Android随笔之——使 ...

  6. 使用CSS3 制作一个material-design 风格登录界面

    心血来潮,想学学 material design 的设计风格,就尝试完成了一个登录页面制作. 这是整体效果. 感觉还不错吧,结尾会附上代码 在编写的过程中,没有使用任何图片或者字体图标,全部使用css ...

  7. C语言 第三章 基础编程测试与练习

    1.屏幕上输出:This is a C program 2.输入两个整数,求两个数的和,如下所示:请输入第1个数:5请输入第2个数:3 3加5的和是8 3.完成华氏温度与摄氏温度间的转换,如下所示:请 ...

  8. 移动端(h5)开发笔记

    1.禁止缩放+禁止缓存 <head> <meta charset="UTF-8" /> <meta name="viewport" ...

  9. (十三)WebGIS中工具栏的设计之命令模式

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 从这一章节开始我们将正式进入WebGIS的工具栏中相关功能的 ...

  10. C#文件相同性判断

    在进行开发时,对文件进行上传和下载是较为普遍的行为,为了防止在文件操作过程中,出现同一文件多次操作,需要对文件进行相同性比较: 1.获取文件的绝对路径,针对window程序和web程序都可使用: // ...