Android 检测内存泄漏,必须使用方便强大到灭绝人性的 leakcanary。javascript
leakcanary 是 square 公司开发的,square 拥有众多强大的 Android 开源项目,如,OkHttp、retrofit、otto、picasso,简直撑起了Android 开发的半边天。java
一行代码就能够捕找到已经泄漏的内存泄漏,而且显示出出现内存泄漏的变量或线程、泄漏时的引用路径和出现泄漏的地方。android
1.添加依赖git
dependencies {
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.初始化 leakcanarygithub
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
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...
}
}复制代码
写一段内存泄露的代码。app
MainActivity.javaide
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
test();
finish();
startActivity(new Intent(MainActivity.this, Main2Activity.class));
}
// 这里会发生内存泄漏
public void test() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}复制代码
MainActivity 中点击按钮后,'test()' 方法内部匿名内部类执行了耗时任务,而且同时 finish()
掉 MainActivity,可是此匿名内部类依然在运行任务,而且隐式的持有 MainActivity 引用,致使 MainActivity 不能及时被 GC 回收,致使内存泄露。this
LeakCanary 检测出内存泄露后,会在状态栏显示一条通知,点进去就能够看到详细信息。以下图:spa
含义:线程
标题栏显示内存泄露的类和泄露的内存大小,菜单栏提供分享出更详细的信息,包括堆栈信息或者 .hprof
文件。蓝色栏显示包名,第一行显示出现泄露的线程,下面几行显示全部的引用,最后一行显示泄露的类。
MainActivity$1.this$0
的含义:
符号 “$” 表明后者是前者的内部类,“.”就是对象调用方法那个点。
用 “.” 分为两部分,前面总体表明 MainActivity 的一个匿名内部类,用 1 表示,在这里表明 Runnable 匿名类,后面部分 this$0
总体表明外部类。
看到这个内存泄露信息,首先定位到 MainActivity 中,同时能够看得出是 MainActivity 的实例出现的内存泄露,而且发生在子线程中,看到代码,咱们就能够确认确定是在 Runnale 匿名内部类中隐式的引用了 MainActivity 致使的内存泄露。
在这里打一个断点:
能够看到匿名类内部存在一个外部 MainActivity 的引用。
找到缘由就好办了,静态化匿名内部类就解决问题了:
// 静态
public static void test() {
// ...
}复制代码
静态化以后,发现该匿名内部类中不在持有外部类 MainActivity 对引用,也就不会在 MainActivity 销毁后,出现内存泄露了。
本文由 Bakumon 创做,采用 知识共享署名4.0 国际许可协议进行许可本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名