原文地址:

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. java的栈图形演示

    import java.awt.*; import javax.swing.*; import java.awt.event.*; /* 指示发生了组件定义的动作的语义事件.当特定于组件的动作(比如被 ...

  2. android图片透明度跟缩放大小动画事件

    概序 : 动画事件写在xml中,然后用AnimationUtils去加载动画事件,再监听动画结束事件,隐藏imageview. 1. player_double_click_animation.xml ...

  3. JavaScript中的日期处理注意事项

    在业务逻辑比较多的系统里面,一般都会涉及到日期的处理.包括选择起始日期和结束日期,结束日期要大于起始日期,日期的显示和输入等. 输入这一块基本都是使用jQuery datetimepicker,后来系 ...

  4. JavaScript阻塞剖析与改善

    一.阻塞特性 <高性能JavaScript>一书中,关于第一章“Loading and Execution”,提到了无阻塞加载JavaScript技术,目的是为了提高页面呈现速度. 说到无 ...

  5. 关于SubSonic3.0插件使用SubSonic.Query.Select查询时,字段类型为tinyint时列丢失问题的Bug修复

    下午在写代码时,突然发现一个列名为Enable的字段怎么也查询不出来,开始以为可能这个名称是关键字,所以给过滤掉了,所以就将名称修改为IsEnable,问题还是一样......将名称又改为IsEnab ...

  6. C算法编程题(三)画表格

    前言 上一篇<C算法编程题(二)正螺旋> 写东西前还是喜欢吐槽点东西,要不然写的真还没意思,一直的想法是在博客园把自己上学和工作时候整理的东西写出来和大家分享,就像前面写的<T-Sq ...

  7. 使用Windows EFS(怎么给文件夹加密)进行文件加密

    和Windows BitLocker一样,Encrypting File System(EFS,加密文件系统)是Windows内置的一套基于公共密钥的加密机制,可以加密NTFS分区上的文件和文件夹,能 ...

  8. C# 提取Word文档中的图片

    C# 提取Word文档中的图片 图片和文字是word文档中两种最常见的对象,在微软word中,如果我们想要提取出一个文档内的图片,只需要右击图片选择另存为然后命名保存就可以了,今天这篇文章主要是实现使 ...

  9. 在IIS EXPRESS下运行一个visual studio 项目,跳转到另一个项目的解决方案。

    原因是因为以前有一个项目也是3690端口,然后在3690端口上建立了一个网站,现在的新网站也是用的3690端口,那么会调用以前网站的WEB.CONFIG文件. 解决方法,右键单击网站,然后选择属性.在 ...

  10. 30分钟?不需要,轻松读懂IL

    先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用.到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.net理解更深一点这些虚头巴脑的东西.最重要的理由就是一个 ...