Android——Handler内存泄露

来源:互联网 发布:自学网站美工 编辑:程序博客网 时间:2024/06/07 06:56

之前听到这么一句话:

  • Android内存泄露说白了就是长生命周期中存在短生命周期的变量。

内存泄露原因:

Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收。

现在学习一下Handler中内存泄露:

Handler也是造成内存泄露的一个重要的源头,主要Handler属于TLS(Thread Local Storage)变量,生命周期和Activity是不一致的
,Handler引用Activity会存在内存泄露。

Handler 的生命周期与Activity 不一致
- 当Android应用启动的时候,会先创建一个UI主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。
- 当在主线程中初始化Handler时,该Handler和Looper的消息队列关联(没有关联会报错的)。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。

缕通啦:
- Android应用启动时,创建的Looper对象,Looper生命周期是最长的与整个应用的生命周期相同。
- 应用可能有多个Activity,当AtyA中 new Handler时,这时该Handler隐式地持有这个AtyA对象。比如这时Handler在一个新线程处理一个比较耗时操作,但在处理过程中,AtyA finish()了 ,当新线程的Handler处理完操作后sendMessage给AtyA时,引用了AtyA的Handler对象,然后这个Handler又引用了这个AtyA。 这些引用对象会保持到该消息被处理完。AtyA对象无法被系统回收,这时就导致了内存泄露。
- 解释之前那句——在长生命周期中调用了短生命周期的值。

handler 引用 Activity 阻止了GC对Acivity的回收

  • 在Java中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象。
  • 如果外部类是Activity,则会引起Activity泄露 。
  • 当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

内存泄露的危害

  • 内存泄露的危害就是会使虚拟机占用内存过高,导致OOM(内存溢出),程序出错。

  • 对于Android应用来说,就是你的用户打开一个Activity,使用完之后关闭它,内存泄露;又打开,又关闭,又泄露;几次之后,程序占用内存超过系统限制,FC。

找到原因啦,解决方案

方法一:通过程序逻辑来进行保护。

  1. 在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。

  2. 如果Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。

@Override  public void onDestroy() {      //  If null, all callbacks and messages will be removed.      mHandler.removeCallbacksAndMessages(null);  }

方法二:将Handler声明为静态类
PS:在Java 中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,静态的内部类不会持有外部类的引用。

  • 静态类不持有外部类的对象,所以你的Activity可以随意被回收。由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)。
static class MyHandler extends Handler    {        WeakReference<Activity> mWeakReference;        public MyHandler(Activity activity)         {            mWeakReference=new WeakReference<Activity>(activity);        }        @Override        public void handleMessage(Message msg)        {            final Activity activity=mWeakReference.get();            if(activity!=null)            {                if (msg.what == 1)                {                    noteBookAdapter.notifyDataSetChanged();                }            }        }    }
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 无线pos机连接主机失败怎么办 水墨晕染模板用不了怎么办 申请入驻饿了么失败怎么办 天猫流量大淘宝怎么办 拼多多商家不退款怎么办 苹果手机开流量显示e怎么办 苹果手机有服务流量打不开怎么办 苹果七plus流量打不开怎么办 苹果手机突然打不开流量怎么办 天猫商家迟迟不发货怎么办 苹果7开不开机了怎么办 苹果机黑屏了开不起来怎么办 美团收银机连不上网怎么办 6s换电池后黑屏怎么办 苹果上的软件打不开也删不掉怎么办 苹果手机打开软件打不开怎么办 苹果电脑下载的软件打不开怎么办 苹果手机下载的软件都打不开怎么办 苹7果屏幕黑屏怎么办 苹果6s手机打不开怎么办 苹果ipad密码输入打不开怎么办 苹果平板黑屏了打不开怎么办 苹果6sp电影商城打不开怎么办 苹果6应用商城打不开怎么办 游戏下载好了安装不上怎么办 苹果5s应用商店不见了怎么办 id被停用手机白板打不开怎么办 苹果6s下载不了软件怎么办 苹果下载的软件打不开怎么办 苹果6s下不了app怎么办 苹果手机因为闪退打不开了怎么办 天猫方糖坏了怎么办 天猫魔盒的遥控器坏了怎么办 天猫盒子没声音怎么办 天猫魔盒播放声音很低怎么办 天猫魔盒3a卡顿怎么办 天猫网络机顶盒打不开了怎么办 天猫机顶盒遥控器丢了怎么办 天猫机顶盒没有遥控器怎么办 天猫机顶盒很卡怎么办 天猫机顶盒没遥控器怎么办