2015-09-04 193 views
11

我試圖實施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自定義選項卡庫本身的錯誤?

謝謝。

回答

2

示例中的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

1

找到這個問題的答案 -

如果您正在啓動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