Handler造成Activity泄漏,用弱引用真的有用么?

来源:互联网 发布:电子菜谱制作软件 编辑:程序博客网 时间:2024/05/20 18:19

网上很多教程,解决Handler造成的内存泄漏问题,基本上是使用弱引用来解决的,但是使用弱引用真的有效么?直接写代码演示,以及分析。

  • 下面分析过程分为4种,第一种是Handler声明成静态的并且弱引用Activity。第二种是handler声明成成员变量的,使用弱引用。第三种是将handler声明成静态的。第四种是声明成普通成员变量,但是在onDestory中移除未执行完的任务。

    • 第一种 Handler声明成静态的并且弱引用Activity
    • 下面是代码

      `   public static   class UIHndler extends android.os.Handler{WeakReference<MainActivity> softReference;public UIHndler(MainActivity mainActivity){    softReference=new WeakReference<MainActivity>(mainActivity);}@Overridepublic void handleMessage(Message msg) {    super.handleMessage(msg);    MainActivity mainActivity = softReference.get();    if(mainActivity!=null){        // 更新ui        mainActivity.handler();    }}}`
    • 这种是我们经常写的代码,也是网上很多教程这样写的
    • 下面是执行前和执行后的效果图,我们横竖屏切换来完成这个操作。
    • 这张图是Activity启动的图 
    • 可以看到,初始申请内存是3.6m左右。接下来 我们反复的横竖屏切换,拿到下图 
    • 发现内存没有太多,接下来我们运行下GC,看到下图 
    • 发下确实没有造成内存泄漏,但是这样能说是弱引用的原因么?因为我们的Handler声明成静态的了
  • 接下来我们演示第二种情况。handler声明成成员变量的,使用弱引用

    • 下面是代码

        public    class UIHndler extends android.os.Handler{    WeakReference<MainActivity> softReference;    public UIHndler(MainActivity mainActivity){        softReference=new WeakReference<MainActivity>(mainActivity);    }@Overridepublic void handleMessage(Message msg) {    super.handleMessage(msg);    MainActivity mainActivity = softReference.get();    if(mainActivity!=null){        // 更新ui        mainActivity.handler();    }}}
    • 接下来我们还是横竖屏切换,看看内存申请


* 接下来我们Gc


* 发现内存并没有少,这是因为在 hanlder中有延迟任务。那么等延迟任务执行完了之后我们在GC下。下图等延迟任务执行万之后的是GC效果

  • 发现也没有造成内存泄漏,但是得等到handler中的任务都执行完成之后才会清除内存。这样的话性能还是比较低,当然也没有造成内存泄漏。

    • 接下来演示第三种情况 将handler声明成静态的
  • 下面是我们的代码

    public static android.os.Handler handler=new android.os.Handler(){    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        tv.setText("dsa");    }}; 
  • 也是反复的横竖屏切换

  • 接下来gc

  • 发现只要handler声明称static的就不会造成内存泄漏,而且回收很快

那么通过上面的三种情况我们发现。只要是handler声明成static就不会造成内存泄漏,声明成弱引用activity的话,虽然也不会造成内存泄漏,但是需要等到handler中没有执行的任务后才会回收,因此性能不高。

handler之所以造成内存泄漏是因为在activity销毁的时候,handler中有未执行完的任务。那么接下来我们在Activity销毁的时候清空handelr没有执行的任务会是什么效果

  • 接下来我们看第四种情况

    • handler代码如下

          public static android.os.Handler handler=new android.os.Handler(){    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        tv.setText("dsa");    }};  
    • 但是我们在activity的onDestory中添加了如下代码,清空所有handler中没有执行完的任务

         protected void onDestroy() {    super.onDestroy();    handler.removeCallbacksAndMessages(null);}
    • 下面是反复横竖屏内存图

  • 下面是GC之后的 
  • 发现也没有内存泄漏

总结

  • handler造成内存泄漏是因为在Activity销毁的时候还有未执行完的任务
  • 静态static可以解决内存泄漏
  • 使用弱引用也可以解决内存泄漏,但是需要等到handler的中任务都执行完,才会释放activity内存,不如直接static释放的快
  • handler造成内存泄漏有 两种方案:一种是业务逻辑上,在activity销毁的时候移除所有未执行的任务。一种是从GC上,通过static的Handler或者弱引用解决。但是单独的使用弱引用性能不是太高。

==============================================

在handler中不使用弱引用时,用的是“对象.实例变量”来使用的,那么创建完了没有被GC回收那么造成内存泄漏。而使用了static之后,
静态变量属于类,在内存中只有一个复制,只要静态变量所在的类被加载,

static成员变量:

Java类提供了两种类型的变量:用static关键字修饰的静态变量和不用static关键字修饰的实例变量。静态变量属于类,在内存中只有一个复制,只要静态变量所在的类被加载,这个静态变量就会被分配空间,因此就可以被使用了。对静态变量的引用有两种方式,分别是“类.静态变量"和”对象.静态变量"

实例变量属于对象,只有对象被创建后,实例变量才会被分配内存空间,才能被使用,它在内存中存在多个复制,只有用“对象.实例变量”的方式来引用。



阅读全文
0 0
原创粉丝点击