在Android的線程通訊當中,使用頻率最多的就是Android的消息處理機制(Handler.send()、View.post()、Asynctask.excute()等等都使用到了消息處理機制)。Android中UI線程默認實現了該機制,其它工做線程要想跟UI線程同樣擁有該機制,就必須人爲去實現該機制,該機制的實現也至關簡單暫且忽略。對於Android裏的消息處理,涉及到Handler,Looper,Message,Message Queue等概念。java
爲了便於理解Message泄漏,首先看一段Message的源代碼:android
// 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; /** * 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; sPoolSize--; return m; } } return new Message(); }
從以上代碼能夠看到Message類有一個全局的消息池,池的大小爲50,用於存放Message對象。Message引發泄漏的問題就出在這個全局的消息池。咱們知道Java的回收是由GC來進行的,而當咱們強引用着一個對象時,GC是不會將這個對象回收的。正好這個全局的消息池,裏面存儲的Message必然是一個強引用。形成Message泄漏的一個最大的根源是Message的obj字段,這個字段是Object類型的,所以obj的byte數是能夠很大的。安全
有些人可能會說,那我對obj這個參數作弱引用讓GC可以回收好不就得了。這個方法雖然能解決GC的回收,可是有一個致命的問題,就是弱應用是極不安全的,GC想要何時回收弱應用對象就何時回收。因此咱們應該換一個解決方方法,處理完一個Message就從全局當中移除一個。對於這個實現,Android的Handler有三個暴露的方法可供使用,removeMessages(int what)、removeMessages(int what, Object object)和removeCallbacksAndMessages(Object token)。具體使用可見以下代碼:ide
@Override public void handleMessage(android.os.Message msg) { if (msg == null) { return; } removeXXXXX(); } }
removeMessages(int what)和removeMessages(int what, Object object)會調用MessageQueue的removeMessages(Handler h, int what, Object object),該方法源碼以下:oop
void removeMessages(Handler h, int what, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.what == what && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } }
removeCallbacksAndMessages(Object token)會調用MessageQueue的removeCallbacksAndMessages(Handler h, Object object)方法,該方法源碼以下:post
void removeCallbacksAndMessages(Handler h, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycle(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; n.recycle(); p.next = nn; continue; } } p = n; } } }