移动性能测试 Android 内存泄漏之 RD 是如何检测-LeakCanary

易寒 · October 23, 2015 · Last by 郭振华 replied at February 01, 2016 · 2282 hits

square/leakcanary
udacity/Sunshine-Version-2

添加LeakCanary依赖包

在主模块app下的build.gradle下添加如下依赖:

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

这里写图片描述

开启LeakCanary

添加Application子类

首先创建一个ExampleApplication,该类继承于Application,在该类的onCreate方法中添加如下代码开启LeakCanary监控:

LeakCanary.install(this);

这里写图片描述

在配置文件中注册ExampleApplication

AndroidManifest.xml中的application标签中添加如下信息:

android:name=".ExampleApplication"

这里写图片描述

这个时候安装应用到手机,会自动安装一个Leaks应用,如下图:
这里写图片描述

制造一个内存泄漏的点

建立一个ActivityManager类,单例模式,里面有一个数组用来保存Activity

package com.example.android.sunshine.app;

import android.app.Activity;
import android.util.SparseArray;
import android.view.animation.AccelerateInterpolator;

import java.util.List;

/**
* Created by wuxian on 15/10/23.
*/

public class ActivityManager {
private SparseArray<Activity> container = new SparseArray<Activity>();
private int key = 0;
private static ActivityManager mInstance;

private ActivityManager(){}

public static ActivityManager getInstance(){
if(mInstance == null){
mInstance = new ActivityManager();
}

return mInstance;
}

public void addActivity(Activity activity){
container.put(key++,activity);
}


}

然后在DetailActivity中的onCreate方法中将当前activity添加到ActivityManager的数组中:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
ActivityManager.getInstance().addActivity(this);
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.

Bundle arguments = new Bundle();
arguments.putParcelable(DetailFragment.DETAIL_URI, getIntent().getData());

DetailFragment fragment = new DetailFragment();
fragment.setArguments(arguments);

getSupportFragmentManager().beginTransaction()
.add(R.id.weather_detail_container, fragment)
.commit();
}
}

我们从首页跳转到详情页的时候会进入DetailActivityonCreate的方法,然后就将当前activity添加到了数组中,当返回时,我们没把他从数组中删除。再次进入的时候,会创建新的activity 并添加到数组中,但是之前的activity仍然被引用,无法释放,但是这个activity不会再被使用,这个时候就造成了内存泄漏。我们来看看LeakCanary是如何报出这个问题的。

演示

这里写图片描述

解析的过程有点耗时,所以需要等待一会才会在Leaks应用中,当我们点开某一个信息时,会看到详细的泄漏信息:
这里写图片描述

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 23 条回复 时间 点赞

testerhome 官方 Android App 就用了。

This is a test!
来自Android客户端

#1楼 @lihuazhang 我们rd也是用这个

很好用的工具

非常感谢~

谢谢分享,纯干货

什么原理啊 字节码插桩吗

易寒 #10 · October 26, 2015 作者

#9楼 @seveniruby 这个是下一步要去研究的,我也想知道原理是啥

赞,我们也用这个

易寒 #12 · October 27, 2015 作者

#11楼 @sunrise 是自己拉代码,自己加。还是rd直接打有leakcanary的包

#12楼 @doctorq 是单独拉了一个分支,自己打的包。

易寒 #14 · October 27, 2015 作者

#13楼 @sunrise 有什么缺点?还是用的很好,能发现很多问题?

#14楼 @doctorq 确实能发现一些问题,但也不是很多,很多时候就算发现问题也不能直接定位,还是得用mat去分析。

易寒 #16 · October 28, 2015 作者

#15楼 @sunrise 希望能分享一个用leakcanary发现但是用mat去定位的例子,让我们也学习学习啊

#16楼 @doctorq 跟着RD哥哥学习中,还没完全学会,不敢班门弄斧

leakcanary本质上就是mat来分析,所以太耗手机性能。

请教一个问题啊,我按照这么操作怎么没有看到有自动安装leaks呢?

易寒 #20 · October 31, 2015 作者

#19楼 @tunsuy 用的是什么版本的leaks的

#20楼 @doctorq 哦,刚已经可以了,要重启一下手机才能看到,我用的是华为手机,不知道其他手机是不是也要重启才能看到

易寒 #22 · November 13, 2015 作者

#9楼 @seveniruby 原理是在onDestory方法中,创建一个弱引用的实例,监控当前对象,在后台扫描该对象的引用是否自己释放,如果没有释放的话,会强制执行一次GC,然后的工作就交给类似MAT的工具,没有用到字节码插桩

关于 上传文件到服务器的这块有研究吗? myServer.uploadLeakBlocking(heapDump.heapDumpFile, leakInfo);
这个myServer是如何定义的,有了解的吗?谢谢了!

恒温 感谢 fir.im —— 结果公布 中提及了此贴 05 Jun 13:20
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up