1.gradle 引用
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1' //testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
2.使用
在自己的Application的onCreate()中调用
if (AppConfig.IS_DEBUG) { refWatcher = LeakCanary.install(this); }
AppConfig.IS_DEBUG是我定义的一个常量,在buildTypes进行赋值,进行自己来管理DEBUG状态
buildTypes { release { minifyEnabled false signingConfig signingConfigs.debug proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField "boolean", "IS_DEBUG", "false" buildConfigField "boolean", "IS_LOG", "false" } debug { signingConfig signingConfigs.debug buildConfigField "boolean", "IS_DEBUG", "true" buildConfigField "boolean", "IS_LOG", "true" } }
3.典型泄露
3.1查看泄露情况
简单情况下,是用了leakcanary,运行程序时会在测试机上安装一个APP,可以在这里查看。
也可以通过,Android studio来查看详情,打开这个路径
打开后,找到设备中,对应APP的hprof文件
双击hprof文件,打开
打开分析,然后运行
就可以看到具体的泄漏情况了
3.2工具类静态变量,使用非Application上下文创建泄露
这是我定义的一个toast工具类,static Toaster mToaster;mToaster是static的,因为它的生命周期是跟随Application 的,如果使用activity之类来创建,就会在activity销毁后还保留该activity的引用,就导致了泄露。
public class Toaster { private Toast mToast; private Handler mHandler; private TextView mText; private Runnable lastRun; private Toaster(){ Looper mainLooper = Looper.getMainLooper(); mHandler=new Handler(mainLooper); } private static Toaster mToaster; public static Toaster getToaster(){ if (mToaster == null) { mToaster=new Toaster(); } return mToaster; } public void show(final String text){ if (!TextUtils.isEmpty(text)){ if (mToast == null) { mToast=new Toast(App.instance); LayoutInflater mInflate= (LayoutInflater) App.instance.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View inflate = mInflate.inflate(R.layout.toast_layout, null); mText = ((TextView) inflate.findViewById(R.id.message)); mToast.setView(inflate); mToast.setDuration(Toast.LENGTH_SHORT); //mToast.setGravity(Gravity.CENTER_HORIZONTAL,0,0); } if (lastRun != null) { mHandler.removeCallbacks(lastRun); } mHandler.post(lastRun= new Runnable() { @Override public void run() { mText.setText(text); mToast.show(); } }); } } }
3.3 MediaPlayer的内存泄漏
mediaPlayer使用,释放不正确导致泄露,正确的写法应该这样
if (mediaPlayer != null) { mediaPlayer.stop(); /*查看了Mediaplayer的源码,发现存在一个引用,应该回收,但是在release方法中,并没有没处理,只有在reset方法中,这个引用才被消除。 */ mediaPlayer.reset(); mediaPlayer.release(); mediaPlayer = null; }