Chrome自定义标签中检测到内存泄漏

时间:2015-09-04 21:10:39

标签: android google-chrome memory-leaks chrome-custom-tabs

我试图通过LeakCanary实施Chrome自定义标签并检测内存泄漏。

除非我们添加另一个Activity层(即MainActivity启动Activity2,它绑定/取消绑定到自定义标签服务并启动网址,所以演示应用程序似乎没有泄漏 - MainActivity 1}}在demo app中执行。

MainActivity如下所示:

public class MainActivity extends Activity implements OnClickListener {
    private Button mLaunchButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LeakCanary.install(getApplication());

        setContentView(R.layout.main);

        mLaunchButton = (Button) findViewById(R.id.launch_button);
        mLaunchButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int viewId = v.getId();

        if (viewId == R.id.launch_button) {
            Intent intent = new Intent(getApplicationContext(), Activity2.class);
            startActivity(intent);
        }
    }
}

Activity2返回MainActivity会导致此泄漏:

09-04 13:49:26.783  10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ In org.chromium.customtabsclient.example:1.0:1.
09-04 13:49:26.783  10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * org.chromium.customtabsclient.Activity2 has leaked:
09-04 13:49:26.783  10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * GC ROOT android.support.customtabs.CustomTabsClient$1.val$callback (anonymous class extends android.support.customtabs.ICustomTabsCallback$Stub)
09-04 13:49:26.783  10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * references org.chromium.customtabsclient.Activity2$2.this$0 (anonymous class extends android.support.customtabs.CustomTabsCallback)
09-04 13:49:26.783  10456-12161/org.chromium.customtabsclient.example D/LeakCanary﹕ * leaks org.chromium.customtabsclient.Activity2 instance

https://gist.github.com/abvanpelt/ddbc732f31550b09fc27

我的问题是:这是演示应用程序中的错误吗? (也许unbindCustomTabsService()缺少一些必要的拆解?)或者这是Chrome自定义标签库本身的错误吗?

谢谢。

2 个答案:

答案 0 :(得分:3)

找到这个问题的答案 -

如果您按以下方式启动customTab

private void launchChromeCustomTab(final Context context, final Uri uri) {

     mServiceConnection = new CustomTabsServiceConnection() {
        @Override
        public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient client) {
            client.warmup(0L);
            final CustomTabsIntent intent = new CustomTabsIntent.Builder().build();
            intent.launchUrl(context, uri);
            mIsCustomTabsLaunched = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    CustomTabsClient.bindCustomTabsService(context, "com.android.chrome", mServiceConnection);
}

然后你需要将这个mServiceConnection onDestroy方法解除绑定为 -

@Override
protected void onDestroy() {
    super.onDestroy();
    this.unbindService(mServiceConnection);
    mServiceConnection = null;
}

那将停止投掷

android.app.ServiceConnectionLeaked: Activity <Your_Activity> has leaked ServiceConnection 

答案 1 :(得分:2)

示例中的MainActivity将CustomTabsServiceConnection和CustomTabsCallback的实例创建为匿名内部类。

如果将它们更改为静态内部类,因此删除对MainActivity的this引用,并将对MainActivity的引用设置为WeakReferences,您将看到LeakCanary停止报告MainActivity泄漏。

现在,如果将其设置为观察该对象,您可能仍会看到有关ServiceConnection泄漏的泄漏金丝雀报告。原因是它与Chrome服务相关联,并且在GC也在服务器端运行之前无法通过GC进行清理。

我创建了一个测试,在一个循环中绑定和取消绑定服务,并且我已经确认ServiceConnections确实在一段时间后被收集了。

因此,可以改进Demo以避免ServiceConnection持有对MainActivity的引用,避免在服务断开后很长时间内有一个像Activity一样繁重的对象,并且它不是自定义标签库的问题。