Bootstrap

Android之内存泄露LeakCanary检测

之前有一篇文章提到内存泄露,如果你还不知道安卓中内存泄露是怎么回事,可以去看:
Android之内存泄露与内存管理
http://blog.csdn.net/u014639129/article/details/52735850

那么知道了内存泄露,那么如何避免呢?或者说,我们怎么确定我们的APP没有内存泄露的现象呢?

下面,我们使用LeakCanary来检测并且找出内存泄露的bug。

下面,我们首先模拟一个简单的内存泄露,static静态常量(长生命周期对象)引用Activity(相对static来说,属于短生命周期对象)导致的内存泄露。

public class Constant {
    public static List<Activity> activityList  = new ArrayList<>();
    public static void add(Activity activity){
        activityList.add(activity);
    }
}

这是一个Constant常量类,可以看到我们用一个static的List去装载Activity。

public class MainActivity extends AppCompatActivity {

    private List<String> list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i = 0; i < 100000; i ++){//这里for循环,仅仅是为了看到内存的明显的增长
            list.add(new String(i+""));
        }
        Constant.add(this);//这里把Activity加入到static常量数组
    }
}

代码解释的很清楚也很简单。

我们运行APP,关闭,运行,关闭,反复执行几次

这里写图片描述

内存持续增长,而没有下降

这里写图片描述

甚至还出现了无响应

我们从代码里,很明显的能找到这样的一个内存泄露:
list 引用着activity,即使activity被ondestory()了,依然不能释放内存。

如果我们不知道哪里出现了内存泄露,我们如何准确定位找到bug呢?上面已经提到LeakCanary了,没错。

那么,我先运行使用了LeakCanary执行后的效果。

先打开应用,然后关闭,等上数秒的时间,通知栏会弹出通知

这里写图片描述

点击通知,弹出
这里写图片描述

这个结果,相信大家都看明白了吧?
也就是Constant.activityList静态对象引用着MainActivity实例对象。

那么,我们的代码要怎么做呢?非常简单

首先加入依赖包


    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'

然后在Application初始化一下


public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        LeakCanary.install(this);
    }
}

这样就可以了。

心里有底了吗?我们再做一个单例导致的内存泄露实验吧。


public class DataModel {

    private static DataModel sInstance;
    private TextView textView;

    public static DataModel getInstance() {
        if (sInstance == null) {
            sInstance = new DataModel();
        }
        return sInstance;
    }

    public void setTextView(TextView textView) {
        textView = textView;
    }
}
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.tv);
        DataModel.getInstance().setTextView(textView);
    }
}

这里写图片描述

有看到有一条引用链:
sInstance(长生命周期)–>mRetainedTextview->mContext->mBase->MainActivity(短生命周期)

有兴趣的同学,可以知己去测试一些常见的内存泄露哦。

一:LeakCanary到底是什么?
LeakCanary项目是大名鼎鼎的square公司为Java&Android开发提供的一个自动检测内存泄漏的工具,现在很多项目都在引入来提高代码质量,减少不必要的内存泄漏。尽管Java有垃圾回收机制,但是一些无意识的代码经常会导致对象的引用存在超过其生命周期。

二:LeakCanary是怎么运作的?
1.检测一个对象是否是可疑的泄漏对象。
2.如果第一步发现可疑对象,dump内存快照,通过分析.hprof文件,确定怀疑的对象是否真的泄漏。
3.将分析的结果展示。

;