37624127_1408459495645.jpg
文集目录
哈哈,LeakCanary我是啥我就不用说了吧,大名鼎鼎的 jack 大神出品的内存泄露分析工具,还不知道的小伙伴,看过这我的这篇介绍肯定就知道了,出去也好吹水去啦,哈哈哈......
LeakCanary 工具使用很简单,一步一步来就行了,不要有心里负担啊, 想着约 NB 的工具越难学啥的,都是瞎扯淡,好用的工具必须使用简单。
第一步添加 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'
第二部使用
在自定义的 application 中初始化 LeakCanary
public class LeakCanaryApplication extends Application {
private RefWatcher mRefWatcher;
@Override
public void onCreate() {
super.onCreate();
mRefWatcher = LeakCanary.install(this);
}
好了最简单的使用方式就是这样的,看下我的测试demo,application 持有一个 activity 对象,一个最简单的activity 对象内存谢落
public class BActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
MyApplication.getInstance().mActivity = this;
}
然后我们怎么看结果呢,这个和一般的还不一样,要是发生内存泄露,先是会有一个 toast 实体,然后会在桌面上生成一个 LeakCanary 图标,并且会一条通知,我的手机不知道为啥就是收不到通知。我们点击这个 LeakCanary 图标就可以看到具体的信息,这个不要着急,要等一会才有,另外期中的信息会持久保存,不想看以前的可以删掉。
Snip20170917_36.png
我们点击这一条提示,可以看到具体的引用关系
Snip20170917_37.png
这个结果很明显了吧,不过吐槽下,LeakCanary 提示到时快,但是显示内容实在太慢了,我这2-3分钟才出来,大家要耐心......
必须要吐槽
LeakCanary 的确是傻瓜式的,但是太慢,而且默认只是检测 activity 对象,想要检测别的对象,比如fragment 或是大体积集合,就得另写
我们需要获取 LeakCanary 的核心 RefWatcher,就是监视对象用来分析内存泄露,并持有待分析对象的引用
我们在 application 获取 RefWatcher
public class MyApplication extends Application {
public static MyApplication mApplication;
public Activity mActivity;
public List mList;
public RefWatcher mWatche;
@Override
public void onCreate() {
super.onCreate();
this.mApplication = this;
this.mApplication.mWatche = LeakCanary.install(this);
}
public static MyApplication getInstance() {
return mApplication;
}
}
然后我们在页面的销毁生命周期里注册需要观察分析的对象,至于为啥卸载生命周期里,因为这时候我们才要分析啊,我们的注册动作其实就是触发内存泄露分析了
public class BActivity extends AppCompatActivity {
private ArrayList mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
MyApplication.getInstance().mActivity = this;
mList = new ArrayList<>(10000);
MyApplication.getInstance().mList = mList;
}
@Override
protected void onDestroy() {
super.onDestroy();
MyApplication.getInstance().mWatche.watch(this);
MyApplication.getInstance().mWatche.watch(mList);
}
这里我们泄露了一个 activity 和 一个集合对象,不过很遗憾,10次里也就1次能抓到这个集合的内存的泄露,而且速度非常之慢,是在无语了。知道为啥不,因为 LeakCanary 一次只能抓一个内存泄露。然后呢我改成只有集合内存泄露,但是呢,抓是抓到了,但是太他娘的慢了
Snip20170917_39.png
Snip20170917_41.png
引用列表里,没有显示是哪个 activity,由于结果显示的非常之慢,我都不知道这个列表是在哪个 activity 泄露的,要是有多个地方都会有这个数据交互,那还真不知道是谁泄露的。所以我觉得这个工具只适合观察 activity / fragment 对象
另外LeakCanary可以设置一个回调,在抓到内存泄露后会执行一个我们指定的 intentServer
第一步:继承DisplayLeakService,进行自己的处理逻辑,这里我们只是打印出泄漏的信息,heapDump为对应的内存快照,result为分析的结果,leakInfo则是相关的信息
public class MyLeakUploadService extends DisplayLeakService {
@Override
protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
if (!result.leakFound || result.excludedLeak) {
return;
}
Log.d("MyLeakUploadService", "leakInfo=" + leakInfo);
}
}
第二步:改变Application中初始化RefWatcher的方式,第二个参数中传入我们自定义的Service类名:
public class LeakCanaryApplication extends Application {
private RefWatcher mRefWatcher;
@Override
public void onCreate() {
super.onCreate();
mRefWatcher = LeakCanary.install(this, MyLeakUploadService.class);
}
}
优点:
天然对 activity 很友好
傻瓜式,测试都能玩,在手机上页方便查看
缺点:
内容显示是在太慢,没办法 LeakCanary 是在主线程的任务队列中添加了一个级别很低的任务来进行内存分析,所以速度很慢。
对于非 activity 对象的分析效果实在烂,上面这个集合对象的内存泄露,10次里也就分析初一次,显示速度那就更无语了
默认只能分析 activity 对象,非 activity 对象需要自己添加到 watche 里,太麻烦了,失去了抓取的自主性啊,变成手动的 LeakCanary 又有多大意义呢。
结论呢
这个 LeakCanary 平时放里面就好了,测试app 没事时候看一看就得了,完全指望这个不现实,还是自己抓内存快照去扒拉扒拉靠谱,比这快多了。LeakCanary 用作补充即可。
话说还是看接下来的内存分析工具吧,比等着 LeakCanary 慢悠悠的一次给你一条建议,还是自己去抓下内存快照看下来的精准,速度的多。
ps:上面都是我个人的想法,限于使用 LeakCanary 日短,有错误请留言给我,谢谢啦!
参考资料: