Handler内存泄漏的原因是什么?
使用handler时,ide报内存泄漏警告42c27bddab3ceca59705a99da7a1ad5.png这里提醒我们,这个handler必须时静态的,否则有可能会产生内存泄漏,所有的内部类都会引用外部类的引用,为什么只有handler会提示内存泄漏呢?
原因之一内部类持有外部类的引用,这都知道。
因为内部类持有外部类的引用,所以这里可以直接调用到text1.setText("xxx");
要说清除handler内存泄漏的原因,这里就要提到JVM的垃圾回收机制中GCRoot的概念,有个可达性分析,标记的过程就是基于可达性分析来进行的,什么时可达性分析?就是一个持有链,GCRoot持有的就是可达的,或者时被GCRoot简介持有的,都是可达的,一旦可达,意味这它就被这个GCRoot持有了,被GCRoot持有的对象都是不能够进行垃圾回收的
handler的持有链public class Handler {
.......
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
......
}
public final class Message implements Parcelable {
........
@UnsupportedAppUsage
/*package*/ Handler target;
@UnsupportedAppUsage
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
@UnsupportedAppUsage
/*package*/ Message next;
......
首先匿名内部类持有了外部类的链条,handler持有了Activity,handler->Activity,那handler被谁持有了,看上面的代码,在enqueueMessage的时候msg.target = this;再看Message的类,变量target,就是Handler,所以这里链条就变成了Message->Handler->Activity,那message被谁持有,我们的message入队列的时候,丢给了messageQueue,所以messageQueue持有了message。messageQueue->Message->handler->Activity。
public final class Looper {
.....
final MessageQueue mQueue
public static void loop() {
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
}
}
Looper的loop()操作,会对MessageQueue进行轮询操作,所以是Looper持有了MessageQueue,Looper->messageQueue->Message->handler->Activity。然后就是ActivityThread持有了Looper,ActivityThread->Looper->messageQueue->Message->handler->Activity。
分析:
ActivityThread不会释放Looper,Looper持有的MessageQueue,不会释放,message呢?message会释放吗?
public static void loop() {
......
msg.target.dispatchMessage(msg);
......
msg.recycleUnchecked();
}
在message处理完的时候会被释放,会调用msg.recycleUnchecked();去释放。如果message做了一个定时器,2分钟之后才执行,这个message不会被释放,如果是20分钟,那就意味着这个message会在messageQueue里面至少20分钟,这因为message会持有handler,持有activity,这个时候就是内存泄漏,按道理来说,activity走onDestroy(),就会立即释放,但是由于message间接持有了activity,所以它不会释放,handler导致activity内存泄漏的原因就是因为这个持有链条的存在。
最简单的解决办法就是用static,handle创建的是静态的,就没有问题,不持有外部对象,它是全局的。
网友评论