【拒绝一问就懵】之不可忽视的内存泄露

背景介绍

内存泄漏一种状况是一块内存没有引用指向它,却没被回收,这种状况已经由Java虚拟机的 GC缓存

帮助咱们处理好了,见 【拒绝一问就懵】之你多少要懂点内存回收机制;另外一种属于 逻辑内存泄漏,即一个对象已经再也不被使用了,但它仍然被另外一个被使用中的对象所持有,致使该对象所占用的内存块不能被回收。bash

少部分内存泄漏看不出有什么影响,但若是大量发生,将会明显减小可用内存,致使频繁GC,运行缓慢,严重时将容易引起OutOfMemoryErrorapp

Android中常见的内存泄漏

集合引起的泄漏

一些对象缓存到集合中,当它不在被使用时,没有从集合中移除,就形成了泄漏。异步

Activity中的泄漏

一个Activity中的Context一般会被不少地方引用,若是在Activity执行了onDestory()后这些引用没有被置空,将会致使Activity没法被回收。而Activity中依赖了很对对象,这些对象将都不能被回收,因此必定要十分当心Activity的泄漏。如下几种常见的状况须要注意:ide

  • 当建立一个对象,该对象须要Context做为参数时。当该对象在Activity执行了onDestory()后仍然可到达,那么它持有的Activity就没法被回收。
  • 使用匿名内部类Handler时。Handler会间接的持有外部Activity的引用,当Activity执行了onDestory()后,若Handler中仍然有消息在MessageQueue中,那么该Handler就不能被释放,也就意味着Activity也不会被释放。解决方法:
    • 须要在onDestory()完成前确保Handler没有执行yan shi延时任务,没有被其余地方引用。同时清理Handler中全部任务,调用removeCallbacksAndMessages(null);,该方法参数为空时会移除因此的CallBack和Message。
    • 另外一种方法是自定义一个静态内部Handler,让它持有的Activity为弱引用。
    static class MyHandler extends Handler {
          private final WeakReference<Activity> mActivity;
          public MyHandler(Activity activity) {
              mActivity = new WeakReference<Activity>(activity);
          }
          @Override
          public void handleMessage(Message msg) {
              System.out.println(msg);
              if (mActivity.get() == null) {
                  return;
              }
              mActivity.get().todo();
          }
      }
    复制代码
  • 在异步任务中引用Activity或Context,而没有在Activity销毁前中止线程,就会致使Activity的泄漏。
  • 内部类、匿名内部类会持有外部类的实例,因此在Activity中使用内部类或匿名内部类,而且将该类建立的对象传递给其余对象,若该对象在Activity以外被引用,或是在仍在进行的异步任务中,那么Activity将不能释放。

Bitmap引起的内存泄漏

Bitmap是引用中占用内存的大户,在使用时必定要十分注意。当Bitmap不用时,应该及时调用recycle()释放其申请的内存。post

异步任务引起的泄漏

异步任务若是在它应该中止的时候没有中止,那它自己及它所依赖的对象将都不能被正确的释放。好比上面提到的Activity中的异步任务。ui

好比在Activity中这样来开启一个异步任务:spa

new Thread(()->{
  // doSomething with long-time 
}).start();
复制代码

那么,在Activity已经finish()了,但异步任务中的Runnable还被持有,而且因为是属于Activity的匿名内部类,因此会致使Activity的内存不能及时回收。线程

总结

因为系统内存资源有限,因此咱们须要尽可能避免 内存泄漏,以保证程序可以流畅运行。code

  • 因为Activity泄漏将会连带大量的对象一块儿泄漏,因此在Activity中写代码应该特别注意Handler、内部类及匿名内部类,还有Context不能随便传递。
  • 使用异步任务时必定要明确其做用范围,在应该中止的时候记得中止。
  • Bitmap占用内存一般较大,因此在使用完后及时释放十分重要。
  • 此外,在传递参数到单例中时,也须要谨慎。
相关文章
相关标签/搜索