`
砺雪凝霜
  • 浏览: 151690 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android中的内存泄露

阅读更多

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用。通常我们的代码会这样实现。

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }
}
但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告

In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread’s MessageQueue also retain their target Handler. If the Handler is an inner class, its outer class will be retained as well. To avoid leaking the outer class, declare the Handler as a static nested class with a WeakReference to its outer class
看到这里,可能还是有一些搞不清楚,代码中哪里可能导致内存泄露,又是如何导致内存泄露的呢?那我们就慢慢分析一下。

1.当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作就是一个一个处理消息队列中的消息对象。在Android中,所有Android框架的事件(比如Activity的生命周期方法调用和按钮点击等)都是放入到消息中,然后加入到Looper要处理的消息队列中,由Looper负责一条一条地进行处理。主线程中的Looper生命周期和当前应用一样长。

2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息已经包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用Handler#handleMessage(Message)完成消息的正确处理。

3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。关于这一内容可以查看Java中”失效”的private修饰符解析

确实上面的代码示例有点难以察觉内存泄露,那么下面的例子就非常明显了

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for 10 minutes.
    mLeakyHandler.postDelayed(new Runnable() {
      @Override
      public void run() { /* ... */ }
    }, 1000 * 60 * 10);

    // Go back to the previous Activity.
    finish();
  }
}
     分析一下上面的代码,当我们执行了Activity的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中10分钟,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的SampleActivity的引用,所以这导致了SampleActivity无法回收,进行导致SampleActivity持有的很多资源都无法回收,这就是我们常说的内存泄露。

      注意上面的new Runnable这里也是匿名内部类实现的,同样也会持有SampleActivity的引用,也会阻止SampleActivity被回收。

      要解决这种问题,思路就是不适用非静态内部类,继承Handler时,要么是放在单独的类文件中,要么就是使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。另外关于同样也需要将Runnable设置为静态的成员属性。注意:一个静态的匿名内部类实例不会持有外部类的引用。 修改后不会导致内存泄露的代码如下

public class SampleActivity extends Activity {

  /**
   * Instances of static inner classes do not hold an implicit
   * reference to their outer class.
   */
  private static class MyHandler extends Handler {
    private final WeakReference<SampleActivity> mActivity;

    public MyHandler(SampleActivity activity) {
      mActivity = new WeakReference<SampleActivity>(activity);
    }

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

  private final MyHandler mHandler = new MyHandler(this);

  /**
   * Instances of anonymous classes do not hold an implicit
   * reference to their outer class when they are "static".
   */
  private static final Runnable sRunnable = new Runnable() {
      @Override
      public void run() { /* ... */ }
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for 10 minutes.
    mHandler.postDelayed(sRunnable, 1000 * 60 * 10);

    // Go back to the previous Activity.
    finish();
  }
}
     其实在Android中很多的内存泄露都是由于在Activity中使用了非静态内部类导致的,就像本文提到的一样,所以当我们使用时要非静态内部类时要格外注意,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。个人倾向于使用文章的静态类和弱引用的方法解决这种问题。

 

分享到:
评论

相关推荐

    Android webview 内存泄露的解决方法

    Android webview 内存泄露的解决方法 最近在activity嵌套webview显示大量图文发现APP内存一直在涨,没法释放内存,查了很多资料,大概是webview的一个BUG,引用了activity导致内存泄漏,所以就尝试传递...

    Android处理内存泄漏的代码例子

    Android处理内存泄漏的代码例子。用于演示避免内存泄漏的几种方法,包括:关闭游标、重用适配、回收图像、注销监听、释放引用。

    Android Native 内存泄漏系统化解决方案

    主要介绍了Android Native 内存泄漏系统化解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    RxJava在Android中内存泄漏解决以及RxJava的封装

    RxJava在Android中内存泄漏解决以及RxJava的封装 原文:http://blog.csdn.net/adzcsx2/article/details/51333890 原作者的demo运行有点问题,本人修复重新上传。

    androidStudio内存泄漏分析

    用AndroidStudio内存泄漏分析,亲测可用,在项目中充分验证。

    android检查内存泄露

    android检查内存泄露和用法 &lt;!--==============================================================================--&gt; android:name="com.squareup.leakcanary.internal.HeapAnalyzerService" android:enabled...

    Android内存泄漏简介

    Android内存泄漏简介 不少人认为java程序,因为有垃圾回收机制,应该没有内存泄漏 1.引用没有释放造成的内存泄漏 2.资源对象没有关闭造成的内存泄漏 3.一些不良代码造成的内存压力 4.JNI代码的内存泄漏

    android系统分析内存泄露测试

    android系统分析内存泄露测试android系统分析内存泄露测试android系统分析内存泄露测试

    使用Android Studio检测内存泄露(LeakCanary)

    本篇文章主要介绍了用Android Studio检测内存泄露的问题的解决方法,Android Studio在为我们提供了良好的编码体验的同时,也提供了许多对App性能分析的工具,下面我们一起来了解一下。

    Android解决大量帧动画内存泄漏问题

    帧动画太多造成内存泄漏问题,内含所需的JAR包:org.apache.commons.io.IOUtils,将Inputstream转为byte字节数组,减少内存泄漏 和关键代码,仅供参考,如有建议请在下方留言或添加咨询~~~

    Android 内存泄露原因分析

    Android 内存泄露原因分析。通过原因分析,再接合代码可查明具体原因,发现对策

    android内存泄露测试

    android 内存泄露测试.

    Android 内存泄露 Mat工具分析

    Android 内存泄露 Mat工具分析。非常好的分析工具讲解

    android应用内存泄露

    android的内存泄露问题,教你如何避免内存泄露 优化程序

    android内存泄露:4、Toast的错误使用导致内存泄露

    详细可参考博文:原创 android内存泄露:3、Handler的错误使用导致内存泄露 ,这篇文章我们将介绍:Toast的错误使用导致内存泄露 二、Toast的错误使用导致内存泄露 我们通常,连续点击按钮多次提示的 Toast,它...

    基于Android Ndk/Jni的内存泄漏检测

    附件是Android下检测ndk和jni内存泄漏的demo,可以用于native中malloc和free的检测。使用方法(参见博客):https://blog.csdn.net/zhuyong006/article/details/88537499

    Android内存OOM优化详解.pdf

    Android 内存 OOM 优化和治理,Android 内存泄漏原因详解与应对措施,Android 中的 Bitmap 使用详解,Android 中的 Bitmap 内存治理和优化详解,Android 内存分析命令详解,Java内存模型。Android 内存 OOM 优化和...

    Android应用程序内存泄漏的分析.pdf

    Android应用程序内存泄漏的分析.pdf

    android 内存泄漏 摘抄

    android 的内存泄漏 和anr的处理情况,挺不错的资源

Global site tag (gtag.js) - Google Analytics