你的位置:首页 > 操作系统

[操作系统]Android的Message Pool是什么——源码角度分析


原文地址:

      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处理。