浅谈Handler内存泄漏
什么是内存泄漏
- 内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
代码示例
public class MyActivity extends AppCompatActivity
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Message message = Message.obtain();
message.what = 1;
mHandler.sendMessageDelayed(message,10*60*1000);
}
}
Handler内存泄漏原因
- 当Handler消息队列还有未处理的消息或正在处理消息时,存在引用关系:“未被处理或正处理的消息 -> Handler实例 -> 外部类”
- 若出现 Handler的生命周期 > 外部类的生命周期时(即 Handler消息队列还有未处理的消息或正在处理消息而外部类需销毁时),将使得外部类无法被垃圾回收器(GC)回收,从而造成内存泄露
解决办法
- 第一种是使用弱引用
public class MyActivity extends AppCompatActivity {
private NoLeakHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new NoLeakHandler(this);
Message message = Message.obtain();
mHandler.sendMessageDelayed(message,10*60*1000);
}
private static class FHandler extends Handler {
// 定义 弱引用实例
private WeakReference<Activity> reference;
// 在构造方法中传入需持有的Activity实例
public FHandler(Activity activity) {
// 使用WeakReference弱引用持有Activity实例
reference = new WeakReference<Activity>(activity);
}
// 通过复写handlerMessage() 从而确定更新UI的操作
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}
出现内存泄露问提的原因,就是 Handler 对 Activity 是强引用,导致 GC 在回收 Activity 时无法回收。为了解决这个问题,我们可以把 Handler 对 Activity 弱引用,这样 GC 就能把 Activity 及时的回收,从而杜绝了内存泄露的问题。
- 第二种是及时清除消息
public class LeakCanaryActivity extends AppCompatActivity {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Message message = Message.obtain();
message.what = 1;
mHandler.sendMessageDelayed(message,10*60*1000);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
}
即在页面销毁的时候,清除handler中所有的消息。