是什么导致Google AdMob泄漏ServiceConnection?

我在一个片段中使用AdMob。 有时我看到下面的堆栈

10-23 14:27:38.916: E/ActivityThread(21250): Activity com.applegrew.app.skywifiremote.MainActivity has leaked ServiceConnection com.google.android.gms.common.b@420e82e8 that was originally bound here 10-23 14:27:38.916: E/ActivityThread(21250): android.app.ServiceConnectionLeaked: Activity com.applegrew.app.skywifiremote.MainActivity has leaked ServiceConnection com.google.android.gms.common.b@420e82e8 that was originally bound here 10-23 14:27:38.916: E/ActivityThread(21250): at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:979) 10-23 14:27:38.916: E/ActivityThread(21250): at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:873) 10-23 14:27:38.916: E/ActivityThread(21250): at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1690) 10-23 14:27:38.916: E/ActivityThread(21250): at android.app.ContextImpl.bindService(ContextImpl.java:1673) 10-23 14:27:38.916: E/ActivityThread(21250): at android.content.ContextWrapper.bindService(ContextWrapper.java:517) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.identifier.ab(SourceFile:179) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.identifier.aa(SourceFile:207) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.atd(SourceFile:83) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.atb(SourceFile:131) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.aqa(SourceFile:258) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.aqa(SourceFile:195) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.ka(SourceFile:76) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.request.c.f_(SourceFile:99) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.util.b.run(SourceFile:17) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.util.d.call(SourceFile:29) 10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.util.e.call(SourceFile:49) 10-23 14:27:38.916: E/ActivityThread(21250): at java.util.concurrent.FutureTask.run(FutureTask.java:237) 10-23 14:27:38.916: E/ActivityThread(21250): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 10-23 14:27:38.916: E/ActivityThread(21250): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 10-23 14:27:38.916: E/ActivityThread(21250): at java.lang.Thread.run(Thread.java:841) 

从堆栈跟踪看来,泄漏的来源是AdMob代码。 不过,在我的片段中,我有代码销毁碎片销毁时的AdMob视图。

从我的片段摘录。

 @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); initAd(); } private void initAd() { mAdView = (AdView) getView().findViewById(R.id.remote_pager_ad); if (mAdView != null) { AdRequest adRequest = new AdRequest.Builder().addTestDevice( AdRequest.DEVICE_ID_EMULATOR).build(); mAdView.loadAd(adRequest); } } @Override public void onPause() { mAdView.pause(); super.onPause(); } @Override public void onResume() { super.onResume(); mAdView.resume(); } @Override public void onDestroy() { mAdView.destroy(); super.onDestroy(); } 

Solutions Collecting From Web of "是什么导致Google AdMob泄漏ServiceConnection?"

AdMob(Google Play Services)广告泄漏了大量内存,这也是我遇到的类似问题。 使用MAT来发现问题是我的应用程序实例在sComponentCallbacks数组中保留了每个gms广告。 所以我重写registerComponentCallbacks()unregisterComponentCallbacks()来跟踪注册自己但从不注销的实例(当我假设他们应该这样做的时候)。 此代码示例假定只有.gms.ads包是有问题的,但如果您发现其他引起类似泄漏的问题,则也可以将这些包添加到列表中:

 public class MyApplication extends Application { @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void registerComponentCallbacks(ComponentCallbacks callback) { super.registerComponentCallbacks(callback); ComponentCallbacksBehavioralAdjustmentToolIcs.INSTANCE.onComponentCallbacksRegistered(callback); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void unregisterComponentCallbacks(ComponentCallbacks callback) { ComponentCallbacksBehavioralAdjustmentToolIcs.INSTANCE.onComponentCallbacksUnregistered(callback); super.unregisterComponentCallbacks(callback); } public void forceUnregisterComponentCallbacks() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { ComponentCallbacksBehavioralAdjustmentToolIcs.INSTANCE.unregisterAll(this); } } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private static class ComponentCallbacksBehavioralAdjustmentToolIcs { static ComponentCallbacksBehavioralAdjustmentToolIcs INSTANCE = new ComponentCallbacksBehavioralAdjustmentToolIcs(); private WeakHashMap<ComponentCallbacks, ApplicationErrorReport.CrashInfo> mCallbacks = new WeakHashMap<>(); private boolean mSuspended = false; public void onComponentCallbacksRegistered(ComponentCallbacks callback) { Throwable thr = new Throwable("Callback registered here."); ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(thr); if (BuildConfig.DEBUG) Log.w(TAG, "registerComponentCallbacks: " + callback, thr); if (!mSuspended) { if (callback.getClass().getName().startsWith("com.google.android.gms.ads")) { mCallbacks.put(callback, ci); } // TODO: other classes may still prove to be problematic? For now, only watch for .gms.ads, since we know those are misbehaving } else { if (BuildConfig.DEBUG) Log.e(TAG, "ComponentCallbacks was registered while tracking is suspended!"); } } public void onComponentCallbacksUnregistered(ComponentCallbacks callback) { if (!mSuspended) { if (BuildConfig.DEBUG) { Log.i(TAG, "unregisterComponentCallbacks: " + callback, new Throwable()); } mCallbacks.remove(callback); } } public void unregisterAll(Context context) { mSuspended = true; for (Map.Entry<ComponentCallbacks, ApplicationErrorReport.CrashInfo> entry : mCallbacks.entrySet()) { ComponentCallbacks callback = entry.getKey(); if (callback == null) continue; if (BuildConfig.DEBUG) { Log.w(TAG, "Forcibly unregistering a misbehaving ComponentCallbacks: " + entry.getKey()); Log.w(TAG, entry.getValue().stackTrace); } try { context.unregisterComponentCallbacks(entry.getKey()); } catch (Exception exc) { if (BuildConfig.DEBUG) Log.e(TAG, "Unable to unregister ComponentCallbacks", exc); } } mCallbacks.clear(); mSuspended = false; } } } 

然后在我的BaseActivity的onPause() (或onDestroy() )方法中,我调用我的forceUnregisterComponentCallbacks()方法:

 @Override public void onPause() { ((MyApplication) getApplicationContext()).forceUnregisterComponentCallbacks() super.onPause(); } 

请注意,ComponentCallbacks是在ICS中引入的,所以如果您在ICS之前的版本中看到问题,那么这不是问题。

(我也意识到,这并没有解决在OP中确定的确切问题,因为它与bindService() ,而不是ComponentCallbacks ,但是它避免了一个相当大的内存泄漏,迫使我们完全禁用AdMob直到修复可以被释放。)

这看起来像你需要取消注册服务之前,你的活动失去了上下文! 当Activity失败后致电closures时,这与Dialog的问题相同。 : – /