之前有一篇文章提到内存泄露,如果你还不知道安卓中内存泄露是怎么回事,可以去看:
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.将分析的结果展示。