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

12

我正在尝试实现Chrome自定义标签,并通过LeakCanary检测内存泄漏。

除非我们添加另一个Activity层(即MainActivity启动Activity2,绑定/解绑自定义标签服务并启动URL - 执行演示应用程序中的MainActivity所做的一切),否则演示应用程序似乎不会出现泄漏。

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个回答

5
找到了这个问题的答案 -
如果您按照以下方式启动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);
}

然后您需要在onDestroy方法中解除绑定此mServiceConnection -
@Override
protected void onDestroy() {
    super.onDestroy();
    this.unbindService(mServiceConnection);
    mServiceConnection = null;
}

这句话不太完整,可能需要更多的上下文才能正确翻译。
android.app.ServiceConnectionLeaked: Activity <Your_Activity> has leaked ServiceConnection 

3
理想情况下,您希望在onCreate或onStart函数中连接CustomTabs服务,这样Chrome就会在标签页打开之前在后台运行。然而,在launchChromeCustomTab的实现中,似乎是在打开标签页时才连接到服务。这很可能会使连接服务的好处无效,并且与直接创建Intent并调用launchUrl的结果相似。 - andreban
在我看来,CustomTabsServiceConnection除了内存泄漏警告和空闲时间期间大量的GC操作外,没有任何好处,是一个愚蠢的服务。 - LXJ

1
在示例中,MainActivity创建了CustomTabsServiceConnection和CustomTabsCallback的匿名内部类实例。如果将它们更改为静态内部类,从而删除对MainActivity的this引用,并将对MainActivity的引用设置为WeakReferences,您将看到LeakCanary停止报告MainActivity泄漏的情况。现在,如果将ServiceConnection设置为监视该对象,则仍可能会看到leak canary报告有关ServiceConnection泄漏的信息。原因是它链接到Chrome服务,直到GC也在服务器端运行之前,无法通过GC进行清理。我创建了一个测试来循环绑定和解除绑定服务,并确认ServiceConnections确实在一段时间后被收集。因此,Demo可以改进以避免ServiceConnection持有对MainActivity的引用,避免在服务断开连接后长时间保持像Activity这样的重型对象处于活动状态,这不是Custom Tabs库的问题。

谢谢,这个修复了那个漏洞。奇怪的是,我看到了一个不同的漏洞(在这里记录:https://code.google.com/p/chromium/issues/detail?id=473146),它在Chromium 42中得到了修复。我使用的是Chromium 44,仍然看到ResourcesContextWrapperFactory泄漏。 :/ - Allison
作为更新,Github 上的演示应用程序已经更新以避免内存泄漏。 - andreban
无法解决这个泄漏问题,仍在寻找好的解决方案。 我的应用程序也遇到了同样的问题,一直在抱怨<YourActivity>泄漏了ServiceConnection。 - Manisha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接