此文章仅用于个人学习笔记,如有雷同还望见谅
LeakCanary地址:leakcanary
一、使用:
第一步:在build.gradle配置如下:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}
第二步:在Application中添加:
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
上面的配置只是对你的activity的内容中存在的泄露进行了监控,如果有泄露发生,LeakCanary就会弹出一个提示框。当然你也可以对其他对象进行监控,需要用到RefWatcher这个类去主动监控某个对象,比如Fragment。
LeakCanary在调用install方法时会启动一个ActivityRefWatcher类,它用于自动监控Activity执行onDestroy方法之后是否发生内存泄露。如果想要监控Fragment,在Fragment中添加如下的onDestroy方法。
修改如下:
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);
}
/**
* 静态方法来返回全局RefWatcher
*
* @param context
* @return
*/
public static RefWatcher getRefWatcher(Context context) {
MyApplication leakApplication = (MyApplication) context.getApplicationContext();
return leakApplication.refWatcher;
}
}
Fragment对应代码如下:
public class MyFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
MyApplication.getRefWatcher().watch(this);
}
}
最后,安装应用,在debug版本的apk安装后,会出现如下两个图标:左边的是自己应用的图标,右边是启动应用后退出,自动安装的leakCancayDe图标。
二、分析
1、单例所引起的内存泄露
如下一段单例代码:
private static CommUtils instance;
private Context context;
public CommUtils(Context context) {
this.context = context;
}
public static CommUtils getInstance(Context context){
if (instance == null){
instance = new CommUtils(context);
}
return instance;
}
/**该类在MainActivity中的使用如下代码:**/
// CommUtils commUtils = CommUtils.getInstance(this);
上面的这段代码是我们在写单例的时候经常写的,但是在这个单例的使用是存在内存泄露风险的;
原因是:当手机进行横竖屏切换的时候或者Activity过多内存使用紧张的时候,系统销毁Activity,但在这个时候该Activity被CommUtils工具类所持有,导致Activity无法被系统回收从而导致内存泄露
1.1如何解决 (保证Context和AppLication的生命周期一样)
有两种方式解决该单例所导致的内存泄露:
- 第一种方式是使用全局的Application上下文Context参数使用CommUtils,如下:
this.context = context.getApplicationContext(); // or CommUtils commUtils = CommUtils.getInstance(getApplicationContext());
- 第二种方式使用弱引用的方式解决代码如下:
private static WeakReference<CommUtils> WeakReferenceInstance;
private Context context;
public CommUtils(Context context) {
this.context = context;
}
public static CommUtils getInstance(Context context){
if (WeakReferenceInstance == null || WeakReferenceInstance.get() == null) {
WeakReferenceInstance = new WeakReference<CommUtils>(new CommUtils(context));
}
return WeakReferenceInstance.get();
}
}
知识扩展
1、什么是单例模式?
使用时,单例的对象必须保证只有一个实例存在,不予许自由构造对象
确保某个类有且只有一个实例,而且自行实例化并向整个系统提供这个实例
2、什么是内存泄露
当一个对象已经不被使用,本应当别回收,但被另一个正在使用的对象所吃用,导致该对象无法被回收;
网友评论