安卓开发,添加使用最常用的内存泄漏检测LeakCanary。内存泄漏同样也是安卓面试和开发中最常见的问题之一。
一直在使用这个检测内存泄漏,以前只是简单的集成,现在详细总结一下。
参考内存泄漏汇总:
集合类泄漏、单例造成的内存泄漏、非静态内部类创建静态实例造成的内存泄漏、Handler 造成的内存泄漏等。
集成LeakCanary方法: Github中leakcanary代码
1.在module的build.gradle文件里添加依赖如下:
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.AndroidManifest.xml中添加权限 :(文末:Android6.0
的权限动态申请
)
3.1.Android项目中,找到Application类(若没有,则新建并在AndroidManifest中声明),
在Application类onCreate()方法中添加如下代码:
if (LeakCanary.isInAnalyzerProcess(this)) {
return;
}
LeakCanary.install(this);
但是,只能在Activity中进行内存泄漏检测。
3.2.上述默认会检测Activity,但是不会去检测Fragment,若需要对某个Fragment检测,则需要以下代码:
//在自己的Application中添加如下代码
public static RefWatcher getRefWatcher(Context context) {
App application = (App) context.getApplicationContext();
return application.refWatcher;
}
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);
}
//在Activity中添加如下代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始时加入如下两行代码
RefWatcher refWatcher = MyApp.getRefWatcher(this);
refWatcher.watch(this);
//... ...
}
4.检测某个特定的对象,如下代码:
假设对象为mObject
RefWatcher refWatcher = MyApp.getRefWatcher(this);
refWatcher.watch(mObject);
mObject这个对象还在内存中被其他对象引用,就会在 logcat 里看到内存泄漏的提示。
5.Android6.0中的配置
因为Android6.0
的权限需要动态申请
,不仅要在AndroidManifest.xml
中添加权限,而且需要代码中动态申请:
动态申请的代码:
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE" };
public static void verifyStoragePermissions(Activity activity) {
try {
//检测是否有写的权限
int permission = ActivityCompat.checkSelfPermission(activity,
"android.permission.WRITE_EXTERNAL_STORAGE");
if (permission != PackageManager.PERMISSION_GRANTED) {
// 没有写的权限,去申请写的权限,会弹出对话框
ActivityCompat.requestPermissions(activity,
PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
在第一个Activity中调用:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//申请权限
verifyStoragePermissions(this);
}
6.LeakCanary实现原理:
监听:
在Android中,当一个Activity走完onDestroy生命周期后,说明该页面已经被销毁了,应该被系统GC回收。通过Application.registerActivityLifecycleCallbacks()方法注册Activity生命周期的监听,每当一个Activity页面销毁时候,获取到这个Activity去检测这个Activity是否真的被系统GC。
检测:
当获取了待分析的对象后,需要确定这个对象是否产生了内存泄漏。通过WeakReference + ReferenceQueue来判断对象是否被系统GC回收,WeakReference 创建时,可以传入一个ReferenceQueue 对象。当被 WeakReference 引用的对象的生命周期结束,一旦被 GC 检查到,GC 将会把该对象添加到 ReferenceQueue 中,待ReferenceQueue处理。当 GC 过后对象一直不被加入 ReferenceQueue,它可能存在内存泄漏。当我们初步确定待分析对象未被GC回收时候,手动触发GC,二次确认。
分析:
分析这块使用了Square的另一个开源库haha,https://github.com/square/haha,利用它获取当前内存中的heap堆信息的快照snapshot,然后通过待分析对象去snapshot里面去查找强引用关系。