Android学习笔记五:内存泄露

2019-03-27 17:38 阅读 105 次 评论 0 条
版权声明:本文著作权归TeachCourse所有,未经许可禁止转载,谢谢支持!
转载请注明出处:http://teachcourse.cn/2698.html

一、造成内存泄露的原因分析

Android系统虚拟机的垃圾回收是通过虚拟机的GC机制来实现的,GC会选择一些存活的对象作为GC Root,通过对GC的可达性判断是否需要回收。

程序设计者在编写代码的时候,应该尽量将需要被GC回收的对象的引用断开,这些没有与GC Root直接或间接相连的对象可以被GC回收。

  • 强引用,大部分对象持有的引用类型,不再使用的时候,置空更符合垃圾回收器的标准
  • 软引用,持有该引用的对象,在内存不足的情况,垃圾回收器才会回收
  • 弱引用,很容易被垃圾回收器回收的对象,随时都可能被回收
  • 虚引用,用得比较少

二、常用的内存泄露分析工具

Memory Analyzer Tool(MAT)是一款常用的内存分析工具,在Android Studio里面步骤如下:

  • 下载MAT桌面版(https://eclipse.org/mat/downloads.php
  • 从Android Studio获取HPROF文件
  • 将Android dalvik格式的.hprof文件转换j2se格式的.hprof文件
  • 使用MAT打开转换后的.hprof文件,进入分析界面

LeakCanary是一款检查Android应用程序内存泄露的第三方框架,适合检查Activity、Fragment内存泄露,简单方便:

  1. app/build.gradle 中加入引用
    dependencies {
    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
    testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
    }
    
  2. Application

    public class MyApplication extends Application {
     private RefWatcher refWatcher;
     @Override
     public void onCreate() {
         super.onCreate();
         refWatcher= setupLeakCanary();
     }
    
     private RefWatcher setupLeakCanary() {
         if (LeakCanary.isInAnalyzerProcess(this)) {
             return RefWatcher.DISABLED;
         }
         return LeakCanary.install(this);
     }
    
     public static RefWatcher getRefWatcher(Context context) {
         MyApplication leakApplication = (MyApplication) context.getApplicationContext();
         return leakApplication.refWatcher;
     }
    }
    

三、常见的内存泄露场景

  • 资源性对象未关闭。这些资源性对象包括:数据库读写对象、流的读写对象,在使用结束时,应该立即调用它的close()方法将其关闭,然后再置为null
  • 注册对象未注销。这些注册对象包括:注册广播对象、注册观察者对象,在引用对象生命周期结束时,应该立即注销掉
  • 不再使用的Bitmap对象未调用recycle()方法释放内存。
  • 非静态内部类的静态实例长期维持着一个到外部类的引用,阻止外部类被垃圾回收,频繁的创建外部类实例,造成内存泄露。
  • Handler临时内存泄露。非静态的Handler内部类可能长期维持着一个到外部类的引用,正确的做法是使用静态内部类代替,同时在引用Handler的Activity或Service生命周期结束后,应该立即移除消息队列中的消息。
  • 容器中的对象未清理,造成内存泄露。
  • WebView频繁的创建造成你创建泄露。

四、WebView内存泄漏的原因分析及解决办法

Android 5.1及其以上版本,在Activity组件调用WebView加载网页退出后,Activity组件无法被垃圾回收器回收,造成内存泄漏。

原因:可以使用LeakCanary或Android Studio内存监视器查看对象之间的引用关系,因为某个对象没有被释放,同时该对象持有WebView的引用,而WebView又持有Activity的引用,造成Activity退出后被释放。

解决:在Activity组件的onDestroy方法中先将WebView从父容器中移除,然后再调用WebView的onDestroy方法

@Override
protected void onDestroy() {
   super.onDestroy();
   if (mWebView != null) {
      ViewParent parent = mWebView.getParent();
      if (parent != null) {
      //将WebView从其父容器中移除
         ((ViewGroup)parent).removeView(mWebView);

      }
      //移除WebView包含的所有子View
      mWebView.removeAllViews();
      mWebView.destroy();
      mWebView = null;
   }
}

Android 5.1 WebView内存泄漏问题及解决
http://blog.csdn.net/u013085697/article/details/53259116

五、使用Handler需要注意的问题

Handler也可能造成临时性的内存泄露,原因在于Handler持有Activity的引用,Message持有Handler的引用,在Message发送MessageQueue时,可能需要等待消息处理,这时候退出Activity,导致对象没有办法被回收,造成内存泄露

解决办法,将Handler声明成一个静态内部类,然后对持有的对象使用弱引用,同时在Activity退出时,清除消息队列中回调或消息

private static class WeakHandler extends Handler{
    WeakReference<Context> mContext=null;

    public WeakHandler(Context ctx){
        mContext=new WeakReference<Context>(ctx);
    }

    @Override
    public void handleMessage(Message msg){
        super.handleMessage(msg);
    }
}

@Override
public void onDestroy(){
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}
关注公众号 扫一扫二维码,加我QQ

如果文章对你有帮助,欢迎点击上方按钮关注作者

来源:TeachCourse每周一次,深入学习Android教程,关注(QQ1589359239或公众号TeachCourse)
转载请注明出处:http://teachcourse.cn/2698.html
分类:面试题汇 标签:
Android学习笔记十二:Android基础知识 Android学习笔记十二:Android
夏天适合喝冰凉的水、饮料吗?为什么喝冰凉的水反而不解渴 夏天适合喝冰凉的水、饮料吗?为
Handler方法解析 Handler方法解析
Map接口集合方法解析 Map接口集合方法解析

发表评论

呲牙 憨笑 坏笑 偷笑 色 微笑 抓狂 睡觉 酷 流汗 鼓掌 大哭 可怜 疑问 晕 惊讶 得意 尴尬 发怒 奋斗 衰 骷髅 啤酒 吃饭 礼物 强 弱 握手 OK NO 勾引 拳头 差劲 爱你

表情