美文网首页
重谈Handler的内存泄漏

重谈Handler的内存泄漏

作者: 蜗牛是不是牛 | 来源:发表于2023-02-06 14:39 被阅读0次

Handler 的内存泄漏问题

在多线程操作中,handler会使用的非常多,但是每次使用handler你有没有考虑内存泄漏的问题。

如果你使用handler进行操作时,你会发现出现以下提示 This Handler class should be static or leaks might occur (anonymous android.os.Handler)这样的提示。翻译: 由于此Handler被声明为内部类,因此可能会阻止外部类被垃圾回收。 如果Handler使用Looper或MessageQueue作为主线程以外的线程,则没有问题。 如果Handler正在使用主线程的Looper或MessageQueue,则需要修复Handler声明,如下所示:将Handler声明为静态类; 在外部类中,实例化外部类的WeakReference,并在实例化Handler时将此对象传递给Handler; 使用WeakReference对象对外部类的成员进行所有引用。

警告原因:handler没有设置为静态类,声明内部类可能会阻止被GC回收,从而导致内存泄漏

那么为什么会造成内存泄漏呢。 首先来说下什么是内存泄漏 内存泄漏(Memory Leak):指的是程序已经动态分配的堆内存由于某种原因程序未释放或者无法释放,造成系统资源浪费,会造成程序运行缓慢甚至系统崩溃等严重后果。 问题代码:

public class MainActivity extends AppCompatActivity {
 private Handler mHandler = new Handler();
 private TextView mTextView;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 mTextView = (TextView) findViewById(R.id.tv);
 //模拟内存泄漏
 mHandler.postDelayed(new Runnable() {
 @Override
 public void run() {
 mTextView.setText("yiyi");
 }
 }, 1000);
 }
} 

内存泄漏原因

从上面问题代码,可以看出这里通过内部类方式创建handler,而在java中,非静态内部类会持有外部类的引用,这里的postDelayed是一个延迟处理消息,将一个handler装入到message中,将消息放进消息队列messageQueueLooper进行取消息进行处理。如果此时activity要退出了,想要调用**destroy**销毁,但是此时Looper正在处理消息,**Looper**的生命周期明显比activity长,这将使得activity无法被**GC**回收,最终造成内存泄漏。并且此时handler还持有activity的引用,也是造成内存泄漏的一个原因(不是根本原因)。

但是我觉得真正handler造成内存泄漏的根本原因是生命周期比activity长,比如TextView也是内部类创建的,那么它怎么没有造成内存泄漏,它也持有外部类Activity的引用,根本原因是它的生命周期比Activity短,Activity销毁时候,它可以被GC回收

总结

当handler有没有处理的消息或者正在处理消息,此时Handler的生命周期明显比Activity长,GC持有Activity与handler两者的引用,导致Activity无法被GC回收,造成内存泄漏。而handler是不是内部类,并不是造成内存泄漏的根本原因。

解决方案

静态内部类+弱引用

将Handler的子类设置成 静态内部类,并且可加上 使用WeakReference弱引用持有Activity实例

原因:弱引用的对象拥有短暂的生命周期。而垃圾回收器不管内存是否充足都会回收弱引用对象。

public class HandlerActivity extends AppCompatActivity  {
 private static class MyHandler extends Handler {
 private final WeakReference<HandlerActivity> mActivity;
 public MyHandler(HandlerActivity activity) {
 mActivity = new WeakReference<HandlerActivity>(activity);
 }

 @Override
 public void handleMessage(Message msg) {
 HandlerActivity activity = mActivity.get();
 if (activity != null) {
 }
 }

 private final MyHandler mHandler = new MyHandler(this);
 private static final Runnable mRunnable = new Runnable() {
 @Override
 public void run() { }
 };
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 mHandler.postDelayed(mRunnable, 1000 * 60 * 1);
 finish();
 }
} 

Activity生命周期结束时,清空消息队列 只需在Activity的onDestroy()方法中调用mHandler.removeCallbacksAndMessages(null);就行了。

@Override
protected void onDestroy() {
 super.onDestroy();
 if(handler!=null){
 handler.removeCallbacksAndMessages(null);
 handler = null;
 }
}

相关文章

  • 重谈Handler的内存泄漏

    Handler 的内存泄漏问题 在多线程操作中,handler会使用的非常多,但是每次使用handler你有没有考...

  • 重谈Handler的内存泄漏

    Handler 的内存泄漏问题 在多线程操作中,handler会使用的非常多,但是每次使用handler你有没有考...

  • java基础

    Handler怎样防止内存泄漏 handler引起内存泄漏的原因:由于handler的写法问题,如果handler...

  • app性能优化 - 避免内存泄漏2

    提出问题: Handler造成的内存泄漏问题Handler之所以造成内存泄漏是因为在activity销毁的时候,H...

  • Handler内存泄漏的原因是什么?

    Handler内存泄漏的原因是什么? 这里提醒我们,这个handler必须时静态的,否则有可能会产生内存泄漏,所有...

  • Handler、Looper、message、MessageQu

    最近在写一篇内存泄漏的博客,还在完善中,其中写到handler引起的内存泄漏,发现对Handler了解太过狭隘,于...

  • Android 基础

    1、Android布局 2、Android内存泄漏总结 3 、Handler内存泄漏分析及解决 4...

  • Handler

    一,什么是handler 二,handler的使用 三,handler机制原理 四,handler引起的内存泄漏和...

  • 自定义 Handler 时如何有效地避免内存泄漏问题?

    一般情况下,我们说到 Handler 内存泄漏,指的是 Handler 泄漏掉了所在的 Activity。 上面的...

  • 记录电商公司面试

    面试记录 问了常见的内存泄漏常见有哪些 Handler的内存泄漏情况 activity,window,view之间...

网友评论

      本文标题:重谈Handler的内存泄漏

      本文链接:https://www.haomeiwen.com/subject/mpstkdtx.html