内存泄漏原因概览

来源:互联网 发布:手机简谱制作软件 编辑:程序博客网 时间:2024/04/29 01:34

1、静态变量导致内存泄漏

Activity的Context或this被赋值给一个类的静态变量,因为静态变量时类变量,除非该类在虚拟机中被卸载,否则,Activity永远被强引用,不会被GC掉。

2、属性动画导致的内存泄漏

如果动画无限循环,且没有在onDestroy中退出动画,并且,此Activity的View被动画持有,View又持有Activity,最终Activity无法释放。解决方法是在,onDestroy中调用animotor.cancel()退出动画。

3、内部类导致的内存泄漏(Handler)

private Handler mHandler = new Handler(){        @Override        public void handleMessage(Message msg) {          ...        }};

经常会使用以上匿名类的方式来引用Handler,匿名类是内部类,
只要在对象的上下文(而不是类的上下文)建立内部类就会隐式持有外部引用(在对象实例变量后直接赋值引用、在实例方法中建立匿名类等)。

为啥会导致内存泄漏呢?
当onDestroy方法执行时,如果Handler对象没有被回收,因为它持有Activity的引用,所以Activity就不能被回收。

那为什么Handler对象没有被回收呢?
要知道MessageQueue里面的Message有一个字段是target,它会持有发送它的Handler对象的引用。设想这样一种情况,当大量使用sendMessage发送信息时,MessageQueue就会有大量Message对象,如果此时关闭Activity,那么这些Message对象就会得不到处理,他们持有Handler对象引用,Handler对象又持有Activity对象,此时就发生内存泄露了。

解决方法就是,别让Handler对象持有Activity引用:

  • 在关闭Activity时(finish/onStop等函数中),取消还在排队的Message:

    mHandler.removeCallbacksAndMessages(null);
  • 新建一个静态内部类,但是,因为要在Handler的handleMessage中更新UI,静态内部类访问不到外部类的成员,所以就要传入弱引用包装的Activity引用,来更新UI

相关阅读:Android中的内部类引起的内存泄露

4、优先处理的常见的内存泄漏

  1. 非静态内部类导致的内存泄漏,如Handler;
  2. IO操作后没有关闭文件导致的内存泄漏,如Cursor、FileInputStream、FileOutputStream用完没关;
  3. 自定义View中使用TypedArray后,没有recycle;
  4. 某些地方使用了四大组件的context,在离开这些组件后仍然持有其context导致的内存泄露,使用Application的Context就可以解决这类问题,各类组件的Context的应用场景:

    1、数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task,一般情况不推荐;

    2、数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用;

    3、数字3:在Receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视);

    4、ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。

  5. 还有一种不属于内存泄露,但在分析内存泄露的问题时应该一并解决:同一个APP,将图片放在不同的drawable文件夹下,在相同的设备上占用的内存情况不一样。相关阅读:关于Android中图片大小、内存占用与drawable文件夹关系的研究与分析
    • UI只提供一套高分辨率的图,图片建议放在drawable-xxhdpi文件夹下(放在xxxhdpi或者更高分辨率的文件夹下没有必要,权衡利弊,照顾主流设备即可),这样在低分辨率设备中图片的大小只是压缩,不会存在内存增大的情况;
    • 涉及到桌面插件或者不需要缩放的图片,放在drawable-nodpi文件夹下,这个文件夹下的图片在任何设备上都是不会缩放的。

相关阅读:Android应用内存泄露分析、改善经验总结

5、内存泄漏的八种可能

  1. 静态Activity:静态变量引用实例本身
  2. 静态View:view也会持有Activity引用,所以。。
  3. 内部类
  4. 匿名类:匿名AsyncTask
  5. Handler:上面有
  6. 无限循环的Thread,因为在对象上下文定义,所以也会持有Activity引用
  7. 匿名TimerTask
  8. 使用传感器时,注册了监听器,但是没有注销

相关阅读:
Android内存泄漏的八种可能
Eight Ways Your Android App Can Leak Memory

好吧还是胡凯先生总结得好:Android性能优化系列

0 0
原创粉丝点击