LeakCanary在GitHub上地址:https://github.com/square/leakcanary
在app的build.gradle中加入:
dependencies {
//leakcanary内存检测三方库
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中加入(没有则创建):
@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...
}
}
导致内存泄漏的错误代码:
public class LeakActivity extends AppCompatActivity {
private static User mUser;
……
/**
* 非静态内部类引起的内存泄漏
*/
private void innerClassLeak() {
mUser = new User();
}
class User {
private String userName;
}
}
分析结果:
从下往可以看出导致内存泄漏是LeakActivity中private static User mUser;导致。导致该Activity销毁时释放不了.
解决后代码:
private static User mUser;
……
/**
* 非静态内部类引起的内存泄漏
*/
private void innerClassLeak() {
mUser = new User();
}
static class User {
private String userName;
}
}
将非静态类加入static修饰变为静态类,或者去除 private static User mUser; 中static修饰符
导致内存泄漏的错误代码:
/**
* 线程引起内存泄漏
*/
private void threadLeak() {
new Thread(new Runnable() {
@Override
public void run() {
//耗时操作
SystemClock.sleep(10000);//睡眠10s,模拟耗时操作
}
}).start();
}
分析结果:
可以看出内存泄漏的原因是LeakActivity中有个任务导致,当次Activity销毁时,此线程任务未完成,导致此Activity无法释放。
解决后代码:
/**
* 线程引起内存泄漏
*/
private void threadLeak() {
new MyThread().start();
}
static class MyThread extends Thread{
@Override
public void run() {
//耗时操作
SystemClock.sleep(10000);//睡眠10s,模拟耗时操作
super.run();
}
}
自定义线程池工具类来开启此线程也可以。
导致内存泄漏的错误代码:
Handler handler= new Handler();
/**
* Handler导致内存泄漏
*/
private void HandlerLeak() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
handler.postDelayed(this,1000);//每隔1000毫秒,循环发送消息
}
},1000);
}
分析结果:
从下到上可以看出LeakActivity中消息任务导致内存泄漏,此Activity关闭时消息任务还未关闭,导致此Activity未能销毁。
解决后代码:
Handler handler= new Handler();
/**
* Handler导致内存泄漏
*/
private void HandlerLeak() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
handler.postDelayed(this,1000);//每隔1000毫秒,循环发送消息
}
},1000);
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);//remove正在执行的消息任务
}
当Activity销毁时调用关闭所有消息任务
导致内存溢出的错误代码:
/**
* 静态Toast引起的内存泄漏
*/
private void ToastLeak() {
ToastUtils.showToast(this,new Date().getTime()+"");
}
private static Toast toast;
public static void showToast(Context context, String msg){
if(toast==null)
toast = Toast.makeText(context,"",Toast.LENGTH_SHORT);
toast.setText(msg);
toast.show();
}
分析结果:
从下至上看出LeakActivity 中Toast(这里使用了静态Toast) 的Context导致LeakActivity无法销毁,内存泄漏
解决后代码:
/**
* 静态Toast引起的内存泄漏
*/
private void ToastLeak() {
ToastUtils.showToast(this,new Date().getTime()+"");
}
private static Toast toast;
public static void showToast(Context context, String msg){
if(toast==null)
toast = Toast.makeText(context.getApplicationContext(),"",Toast.LENGTH_SHORT);
toast.setText(msg);
toast.show();
}
这里使用的是应用全局的Context。
什么是Context:https://possiblemobile.com/2013/06/context/