转载地址:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0509/2854.html
http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
转自: http://www.jianshu.com/p/7db231163168
前两天,Square开源了一个内存泄露自动探测神器——LeakCanary,它是一个Android和Java的内存泄露检测库,可以大幅度减少了开发中遇到的OOM问题,对于开发者来说,无疑是个福音,下面对该库的readme进行简单的翻译:
“A small leak will sink a great ship.” - Benjamin Franklin
小漏不补沉大船。——本杰明 富兰克林
在项目的build.gradle文件添加:
1
2
3
4
|
dependencies {
debugCompile
'com.squareup.leakcanary:leakcanary-android:1.3'
releaseCompile
'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
}
|
在Application类添加:
1
2
3
4
5
6
7
|
public class ExampleApplication extends Application {
@Override public void onCreate() {
super
.onCreate();
LeakCanary.install(
this
);
}
}
|
当在你的debug构建过程中出现内存泄露时,LeakCanary将会自动展示一个通知栏。
问得好!我们正好写了个博客回答这个问题。 ps:博客在本站的中文地址:LeakCanary:检测所有的内存泄漏
使用一个RefWatcher观察引用什么时候应该被GC:
1
2
3
4
|
RefWatcher refWatcher = {...};
// We expect schrodingerCat to be gone soon (or not), let's watch it.
refWatcher.watch(schrodingerCat);
|
LeakCanary.install() 返回一个先前配置的RefWatcher,它也安装一个ActivityRefWatcher以便在Activity.onDestroy()被调用后自动检测Activity是否出现泄露。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class ExampleApplication extends Application {
public static RefWatcher getRefWatcher(Context context) {
ExampleApplication application = (ExampleApplication) context.getApplicationContext();
return
application.refWatcher;
}
private RefWatcher refWatcher;
@Override public void onCreate() {
super
.onCreate();
refWatcher = LeakCanary.install(
this
);
}
}
|
你可以使用RefWatcher观察Fragment的内存泄露
1
2
3
4
5
6
7
8
|
public abstract class BaseFragment extends Fragment {
@Override public void onDestroy() {
super
.onDestroy();
RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
refWatcher.watch(
this
);
}
}
|
1.RefWatcher.watch()创建一个KeyedWeakReference去检测对象;
2.接着,在后台线程,它将会检查是否有引用在不是GC触发的情况下需要被清除的;
3.如果引用引用仍然没有被清除,将会转储堆到.hprof文件到系统文件中(it them dumps the heap into a .hprof file stored on the app file system.)
4.HeapAnalyzerService是在一个分离的进程中开始的,HeapAnalyzer通过使用HAHA解析heap dump;
5.由于一个特殊的引用key和定位的泄露引用,HeapAnalyzer可以在heap dump中找到KeyedWeakReference;
6.如果有一个泄露,HeapAnalyzer计算到GC Roots的最短的强引用路径,然后创建造成泄露的引用链;
7.结果在app的进程中传回到DisplayLeakService,并展示泄露的通知消息;
你可以在Logcat上看leak trace:
1
2
3
4
5
6
7
8
9
|
In com.example.leakcanary:1.0:1 com.example.leakcanary.MainActivity has leaked:
* GC ROOT thread java.lang.Thread.<Java Local> (named
'AsyncTask #1'
)
* references com.example.leakcanary.MainActivity$3.
this
$0 (anonymous class extends android.os.AsyncTask)
* leaks com.example.leakcanary.MainActivity instance
* Reference Key: e71f3bf5-d786-4145-8539-584afaecad1d
* Device: Genymotion generic Google Nexus 6 - 5.1.0 - API 22 - 1440x2560 vbox86p
* Android Version: 5.1 API: 22
* Durations: watch=5086ms, gc=110ms, heap dump=435ms, analysis=2086ms
|
你也可以分享leak trace和heap dump文件通过action bar的菜单。
随着时间过去越来越多熟知的内存泄露问题被制造商在android开源项目中修复。当这样一个泄露发生时,你能作为一个应用程序开发员来修复它。出于这个原因,LeakCanary有一个内置Android泄露的列表AndroidExcludedRefs.java来监测它,如果你找到一个新的泄露,请用leaktrace创建一个issue,标明设备和Android版本。如果你提供一个heap dump的文件链接就更好了。
这是对于新发布的Android版本来说是特别重要的。你有机会更早地帮助检测新的内存泄露,这有益于整个Android社区。
开发版快照可以通过Sonatype's snapshots repository找到。
有时leak trace不够清晰,你需要使用MAT和YourKit深入研究heap dump。这里教你怎样在head dump找到泄露的实例:
1.找出包com.squareup.leakcanary.KeyedWeakReference下所有实例;
2.对于每个实例,考虑它的key域;
3.找到 KeyedWeakReference 有一个key域等于被LeakCanary报出的引用的key;
4.KeyedWeakReference的referent域是程序中内存泄露的对象;
5.从那时起,问题就转到你的手上了。一个好的开始是找到最短的GC roots的路径(排除弱引用)
DisplayLeakActivity自带一个默认的icon和label,可以通过提供的R.drawable.leak_canary_icon和R.string.leak_canary_display_activity_label来修改:
1
2
3
4
5
6
7
8
9
10
11
|
res/
drawable-hdpi/
__leak_canary_icon.png
drawable-mdpi/
__leak_canary_icon.png
drawable-xhdpi/
__leak_canary_icon.png
drawable-xxhdpi/
__leak_canary_icon.png
drawable-xxxhdpi/
__leak_canary_icon.png
|
1
2
3
4
|
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<resources>
<string name=
"__leak_canary_display_activity_label"
>MyLeaks</string>
</resources>
|
DisplayLeakActivity可以在你的app目录保存7个heap dumps和leak traces,你可以在app中通过提供R.integer.__leak_canary_max_stored_leaks的值改变这个数量:
1
2
3
4
|
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<resources>
<integer name=
"__leak_canary_max_stored_leaks"
>20</integer>
</resources>
|
你可以改变默认的行为去上传leak trace并heap dump到你选择的服务器。
创建你自己的AbstractAnalysisResultService,最容易的方式是在你debug的源码中继承DefaultAnalysisResultService:
1
2
3
4
5
6
7
8
|
public class LeakUploadService extends DefaultAnalysisResultService {
@Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
if
(!result.leakFound || result.excludedLeak) {
return
;
}
myServer.uploadLeakBlocking(heapDump.heapDumpFile, leakInfo);
}
}
|
确定在你正式发布的Application类中使RefWatcher失效:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class ExampleApplication extends Application {
public static RefWatcher getRefWatcher(Context context) {
ExampleApplication application = (ExampleApplication) context.getApplicationContext();
return
application.refWatcher;
}
private RefWatcher refWatcher;
@Override public void onCreate() {
super
.onCreate();
refWatcher = installLeakCanary();
}
protected RefWatcher installLeakCanary() {
return
RefWatcher.DISABLED;
}
}
|
在你的debug的Application类创建一个定制的RefWatcher:
1
2
3
4
5
|
public class DebugExampleApplication extends ExampleApplication {
protected RefWatcher installLeakCanary() {
return
LeakCanary.install(app, LeakUploadService.class);
}
}
|
不要忘记了在你debug的manifest中注册service:
1
2
3
4
5
6
7
8
|
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<manifest xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
>
<application android:name=
"com.example.DebugExampleApplication"
>
<service android:name=
"com.example.LeakUploadService"
/>
</application>
</manifest>
|
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0511/2861.html
原文: Use LeakCanary to Detect Android Memory Leak
不得不承认,长久以来,对于大部分 Android 工程师,分析内存泄露这一问题多少还是显得有些苦巴巴。因为自己去 dump HPROF 文件,再用 MAT 这类工具分析,对于之前没有接触过这方面工作的还是要一定学习成本的。而且因为这些代(da)码(keng)真的是你一行行写(wa)出来的,每个人在查 自己代码的内存泄露问题时候多少都会想着“卧槽这里怎么可能有问题?这可是我亲手写的啊!!!”,这往往就让问题更加难以被发现。
今天,哦不,凌晨了。。。昨天!昨天,Android 开源界最伟(jian)大(zhi)高(kai)效(gua)的公司 Square 又向业界投下一颗重磅炸弹。推出了一个叫 LeakCanary 的玩意儿,可以通过简单粗暴的方式来让开发者获取自己应用的内存泄露情况。而且得益于 gradle
强大的可配置性,可以确保只在编译 debug 版本时才会检查内存泄露,而编译 release 等版本的时候则会自动跳过检查,避免影响性能。当然,理论上在 debug 阶段所有发现的问题也都该在 release 之前解决掉,否则就没有办法显得逼(ku)格(bi)满满了。
这货真的有这么好用?机智的我还是决定写个 demo 跑一下试试:
build.gradle
因为不想让这样的检查在正式给用户的 release
版本中也进行,所以在 dependencies
里添加
1
2
3
4
5
6
|
dependencies {
compile fileTree(dir:
'libs'
, include: [
'*.jar'
])
compile
'com.android.support:support-v13:+'
debugCompile
'com.squareup.leakcanary:leakcanary-android:1.3'
releaseCompile
'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
}
|
接下来,在你的应用里写一个自定义 Application
,并在其中“安装” RefWatcher
:
1
2
3
4
5
6
7
8
9
10
|
public class AppApplication extends Application {
private RefWatcher mRefWatcher;
@Override
public void onCreate() {
super
.onCreate();
mRefWatcher = LeakCanary.install(
this
);
}
}
|
记得把它作为 android:name
配到 AndroidManifest.xml
的 Application
节点下。
大功告成,就是这么简单。。。
造一个内存泄露简直太简单了!(咦,我为什么这么说