LeakCanary 内存泄露检测实践与解决方法总结

建立LeakCanaery的检测环境
1. 修改chrome的build.gradle
apply plugin: 'com.android.application'

dependencies {
    compile fileTree(dir: 'libs', exclude: 'android-support-multidex.jar', include: '*.jar')
    compile 'com.android.support:multidex:1.0.0'
    compile project(':mediaplayer')
    compile project(':web_contents_delegate_android')
    compile project(':browser_I')
    compile project(':chromium_gen')
    compile files('libs/hugo-annotations-1.2.1-sources.jar')
    compile files('libs/decrawso.jar')
    compile files('libs/qihoospeechrecognition.jar')
    compile files('libs/QHStatAgent.jar')
    compile files('libs/adsdk_0.1.16.1125.jar')
    compile files('libs/andfix.jar')
    compile files('libs/opensdk-release.jar')
//添加下面2行
    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
}
2. 修改ChromeApplication.java
    @Override
    public void onCreate() {
        UmaUtils.recordMainEntryPointTime();
        super.onCreate();
        LeakCanary.install(this);
3. 手动测试, 当发生memory leak的时候就会在桌面创建出Leaks图标

经过测试, 确实发现浏览器有不少内存泄露的地方.

LeakCanary 内存泄露检测实践与解决方法总结_第1张图片
memory_leak.png
4. 解决这些问题的code patch
LeakCanary 内存泄露检测实践与解决方法总结_第2张图片
memory_leak_code_patch.png
常见的代码错误汇总
场景1. 进入某个activity, 然后退出, 再进入.
场景2. 频繁退出, 进入浏览器.
1. static 对象持有了具体activity的context

static的对象(生命周期是整个app运行期), 在创建时传入了某个具体的Activity对象, 当这个activity退出时(onDestroy()被调用), 这个activity对象无法被释放.
解决办法: static对象如果要用到context的话, 就要使用applicationContext, 不要使用activity context.

例如:

public class ToastHelper implements BrowserOnDestroyListener {
    private static Toast mToast;

    public void init(Context context) {
        if (mToast == null) {
            try {
                mToast = new Toast(context);
                mToast.setDuration(Toast.LENGTH_SHORT);
                mToast.setView(inflate.inflate(R.layout.transient_notification, null));
            } catch (Exception e) {
            }
        }
    }

//应该改为:
    public void init(Context context) {
        if (mToast == null) {
            try {
                mToast = new Toast(context.getApplicationContext());
                mToast.setDuration(Toast.LENGTH_SHORT);
                mToast.setView(inflate.inflate(R.layout.transient_notification, null));
            } catch (Exception e) {
            }
        }
    }
2. 对单例的Manager, 只调用了addListener(), 忘记在销毁时调用removeListener().

例如:

public class BottomMenuBar extends LinearLayout {
    public BottomMenuBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        setOrientation(HORIZONTAL);
        ThemeModeManager.getInstance().addThemeModeListener(this, true);
    }

//需要添加下面的代码
//否则ThemeModeManager的listeners会一直持有BottomMenuBar的对象, 导致BottomMenuBar被销毁后, 它所占的内存无法被回收.
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        ThemeModeManager.getInstance().removeThemeModeListener(this);
    }

}

refer to:
http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/

======DONE======

你可能感兴趣的:(LeakCanary 内存泄露检测实践与解决方法总结)