在Chrome自定义选项卡中检测到内存泄漏

问题描述:

我试图实施Chrome自定义选项卡并通过LeakCanary检测到内存泄漏。在Chrome自定义选项卡中检测到内存泄漏

演示应用程序不出现泄漏,除非我们添加另一活性层(即MainActivity启动Activity2,其结合/解除绑定到自定义标签服务并启动URL - 一切MainActivity确实在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); 
     } 
    } 
} 

Activity2MainActivity返回将导致此泄漏:

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自定义选项卡库本身的错误?

谢谢。

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

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

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

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

因此,可以改进Demo以避免ServiceConnection持有对MainActivity的引用,从而避免在服务断开连接后很长一段时间内像活动这样的沉重对象处于活动状态,并且这对于自定义选项卡库。

+0

谢谢,这固定了泄漏。奇怪的是,我看到一个不同的泄漏(这里记录:https://code.google.com/p/chromium/issues/detail?id = 473146),它已在Chromium 42中修复。我在Chromium 44上仍然看到一个'ResourcesContextWrapperFactory'泄漏。 :/ – Allison

+0

作为更新,github上的演示应用程序已更新以避免内存泄漏。 – andreban

+0

:(无法对此泄漏问题做任何事情,仍在寻找好的解决方案。 我的应用程序中存在同样的问题,它一直在抱怨 泄漏了ServiceConnection – Manisha

找到这个问题的答案 -

如果您正在启动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 
+0

理想情况下,您希望连接到onCreate或onStart上的CustomTabs服务,因此Chrome会在后台旋转,标签打开。 launchChromeCustomTab上的实现似乎在打开选项卡时连接到服务。这很可能会使连接到服务的好处变得无效,并且与创建Intent并直接调用launchUrl会产生类似的结果。 – andreban