LeakCanary 傻瓜式的内存泄露检测工具

在开发Android应用的过程当中若是须要处理图片或者大量数据的时候,就有可能会遇到OOMjava.lang.OutOfMemoryError),通常出现最多的是在建立Bitmap上,也有多是在内存中处理了大量的数据上。出现OOM应用会直接崩溃,即便没有出现OOM,内存使用过大的时候应用也会出现卡顿。因此内存的优化在开发Android应用时是一个比较重要的任务。
通常会针对Bitamp的内存优化有下面几种方式:javascript

1. 增长进程的内存
2. 使用Bitmap.Config.ALPHA_8(图片失真)
3. 显示的调用System.gc()
4. catch Exception
5. 调用bitmap.recycle()
6. 缩小bitmap的大小(若是是读取的原图是一个大图应该先采用这种方式,Bitmap若是是恰好适配屏幕的就不须要缩小了)
7. 使用弱引用和软引用(google已经不建议使用了,Android的GC效率很是高,只要保证对象没有被引用便可)复制代码

可是咱们忽略掉一个问题就是什么形成了OOM
通常来讲发生OOM崩溃的地方不必定是内存泄露的地方,崩溃的缘由有多是Activity形成的内存泄露,也多是操做数据库形成的内存泄露,当内存已经很是接近峰值的时候,这个时候恰巧要建立一个Bitmap对象就会发生OOM(Bitmap对象占用的内存比较大)。
是什么缘由形成了内存泄露呢?java

内存泄露

咱们知道Android中每一个对象都有本身的生命周期,好比Activity的生命周期最后会调用onDestroy方法作销毁处理,但若是使用Activity中调用了相似于Toast这种对象,就会把这个Activity的引用传给了Toast,而Toast的生命周期不会随着Activity的销毁而销毁,这样就形成了Activity的内存泄露,它会被Toast对象引用,没法被销毁。
常见的内存泄露造成的缘由:android

  • Toast持有Activity的引用
  • 数据库游标Cursor没有关闭
  • Adapter没有复用convertView
  • 对象被生命周期更长的对象引用,Activity被静态集合引用
  • ....

那如何知道应用的内存有没有出现泄露呢?git

监控内存的方式

Heap Dump:常见的内存监控方式是Heap DumpHeap Dump是一种在Java中比较经常使用的检测内存的方式:github

简单来讲就是咱们在一个初始状态A, 在这个时候Dump一次内存,在作了一些操做以后回到状态A,再Dump一次内存。
对两次Dunp的内存数据(hprof)使用分析工具作分析(MAT),根据分析的结果就能知道是否存在内存泄露,这种方式比较复杂和繁琐并非特别易用。算法

Moitors:这是Android SDK自带的内存监控工具,Monitors能检测到内存的变化,好比内存是增长仍是减小。
打开一个Activity会致使内存增长,关闭一个Activity会致使内存减小,反复的作这样的操做,若是每次打开一个Activity再关闭以后增长的内存不会减小就说明这个Activity有可能有内存泄露,再借助log辅助进行检测,就能够发现内存泄露的问题,
这种方式的缺点是并非特别的准确,由于内存的释放和对象的生命周期有关也和GC的调度有关。
另外一种方式就是LeakCanary,LeakCanary是一个简单的,方便的内存检测工具,能够轻易的发现内存问题,还会生成更加简单清晰的报告。数据库

LeakCanary

LeakCanary是一个开源的检测内存泄露的java库。项目地址:github.com/square/leak…
LeakCanary实际上就是在本机上自动作了Heap dump,对生成的hprof文件进行分析,展现分析的结果。和手工分析Heap Dump的方式获得的结果是同样的。只不过这部分的工做彻底自动化完成了。
下面是一个LeakCanary的结果截图:缓存

LeakCanary

从上图能够看到,LeakCanary能清晰简单的展现出那里有内存泄露的问题。那LeakCanary如何使用呢?ide

集成LeakCanary

build.gradle添加依赖:工具

dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
 }复制代码

使用LeakCanary对应用进行检测它会影响程序的性能,尤为是在作Heap dump分析操做时,所以须要在依赖里面指定对应的版本,debug的时候才进行分析,release的时候不能进行分析。
debugCompile可使用检测版本:

com.squareup.leakcanary:leakcanary-android

releaseCompile使用no-op模式,即No Operation Performed就是不会把对应的类库编译,指定类库为无用的指令:

com.squareup.leakcanary:leakcanary-android-no-op

这样就能够指定LeakCanary为无用指令,不会在release的时候进行编译。
Application中加入分析Activity的代码:

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
  }
}复制代码

这样就能够检测全部Activity的内存泄露了。LeakCanary内部实现使用了ActivityLifecycleCallbacks方法监听全部Activity的生命周期。
除了Activity会发生内存泄露之外,其余对象也有可能会出现内存泄露,若是对其余对象进行检测呢?

检测其余对象

LeakCanary中提供了RefWatcher类,能够用来监控全部的对象。
首先实例化RefWatcher:

public static RefWatcher sRefWatcher=LeakCanary.install(mContext);复制代码

对于监控的对象使用:

sRefWatcher.watch(this)复制代码

通常咱们是在对象销毁的时候对对象进行监控,好比内部实现的对于Activity的监控的原理以下:

private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }

        public void onActivityStarted(Activity activity) {
        }

        public void onActivityResumed(Activity activity) {
        }

        public void onActivityPaused(Activity activity) {
        }

        public void onActivityStopped(Activity activity) {
        }

        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }

        public void onActivityDestroyed(Activity activity) {
            ActivityRefWatcher.this.onActivityDestroyed(activity);
        }
    };复制代码

只是在onActivityDestroyed的时候才对于activity进行监控便可。
检测到了内存泄露,若是解决呢?

解决内存泄露

通常状况内存泄露的缘由都是因为引用的使用不当形成的,Android GC可以保证回收循环引用(若是一个循环引用没有外部引用时就会被回收),且Android GC效率很高,固然GC的算法自己也在不停的改进。
通常状况下只须要尽可能避免错误的引用方式带来的内存泄露问题便可:

  • 生命周期长的对象引用生命周期短的对象,好比static的对象群引用Activity
  • 使用Application的Context对象,而不是Activity的Context
  • 避免非静态类的内部类对于类的隐式引用,使用静态的内部类
  • 使用Android的缓存机制,好比ListView的复用机制
  • 手动关闭资源,好比Curous的关闭
  • registerReceiver和unRegisterReceiver成对出现
相关文章
相关标签/搜索