Handler 内存泄露就真的没法回收了吗?

232 阅读1分钟
 网上很多文章都说在Activity里面做handler的postdelay操作;如果在dealy的时间内做退出Activity操作,则Activity泄露了,垃圾回收不了了。我对此有些疑问
 
 Q1:垃圾回收是根据有无GCRoot的引用链来判断heap中的对象是否还存活
 handler泄露的引用链是
 mQueue(final常量) ->msg.target -> handler ->activity
 ,那么delaypost的message在delay时间到了之后,就会从MessageQueue中出队列,然后message 回收,target =null,引用连断开了,Activity按理来说应该被回收了。
 
 Looper中
 public static void loop() {
 ...
 msg.recycleUnchecked();
 ...
 }
 
 Message 中,target 置空了。
 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 = UID_NONE;
    workSourceUid = UID_NONE;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}
 

结论:
1)ActivityA启动ActivityB,ActivityB中点击btn发送一个postDelay 60秒的消息,这个时候按返回键,destroy ActivityB,则ActivityB泄露了;这里发生了内存泄露;如果在这60秒的时间内,发生了GC则这个ActivityB是无法被回收的。60秒过后,ActivityB就可以被回收了,因为msg.target =null了,引用链断了。

2)如果在这60秒内,我们重新打开ActivityB ,申请一块内存。这个时候,发现内存不够了,触发GC,而原先ActivityB占用的内存又无法释放,而恰恰这个时候, GC释放出来的内存依旧不够,则会引发OOM。