网上很多文章都说在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。