MobileAds.registerWebView引发Activity内存泄漏问题及解决方案咨询
解决MobileAds.registerWebView导致的Activity内存泄漏问题
问题描述
在Activity的onCreate方法中调用MobileAds.registerWebView(webView)后,LeakCanary检测到内存泄漏;移除该代码后泄漏提示消失。泄漏链如下(已翻译为中文):
GC根节点: Thread对象 │ ├─ Dk实例 │ 是否泄漏: 否 (PathClassLoader↓ 未泄漏) │ 线程名称: 'CleanupReference' │ ↓ Thread.contextClassLoader ├─ dalvik.system.PathClassLoader实例 │ 是否泄漏: 否 (zzbzz↓ 未泄漏,且类加载器永远不会泄漏) │ ↓ ClassLoader.runtimeInternalObjects ├─ java.lang.Object[] 数组 │ 是否泄漏: 否 (zzbzz↓ 未泄漏) │ ↓ Object[2266] ├─ com.google.android.gms.internal.ads.zzbzz 类 │ 是否泄漏: 否 (类永远不会泄漏) │ ↓ static zzbzz.zza │ ~~~ ├─ com.google.android.gms.internal.ads.zzcfk实例 │ 是否泄漏: 未知 │ 保留16 B在1个对象中 │ ↓ zzasd.zza │ ~~~ ├─ com.google.android.gms.ads.nonagon.signalgeneration.ab实例 │ 是否泄漏: 未知 │ 保留379.4 kB在5156个对象中 │ e是sg.just4fun.tgasdk.ui.HomeActivity的实例,且mDestroyed = true │ ↓ ab.e │ ~ ╰→ xxx.xxx.WebViewActivity实例 是否泄漏: 是 (ObjectWatcher监控到该对象,因为xxx.xxx.WebViewActivity已收到Activity#onDestroy()回调,且 Activity#mDestroyed为true) 保留376.6 kB在5078个对象中 key = 9500b00e-35f4-476d-bb2e-836c21f4c80f watchDurationMillis = 7971 retainedDurationMillis = 2971 mApplication是com.just4fun.tga.App的实例 mBase是androidx.appcompat.view.ContextThemeWrapper的实例
泄漏原因分析
从泄漏链可以看出,广告SDK的静态引用(zzbzz.zza)最终持有了已销毁的WebViewActivity实例,导致GC无法回收该Activity。核心原因是MobileAds.registerWebView会让SDK持有WebView的强引用,而WebView又关联着Activity的上下文,Activity销毁后SDK未及时释放这些引用。
解决方案
1. 升级Google Ads SDK到最新版本
旧版本SDK存在的内存泄漏问题通常会在新版本中修复。打开项目的build.gradle文件,将play-services-ads依赖更新到最新稳定版:
dependencies { implementation 'com.google.android.gms:play-services-ads:22.6.0' // 替换为当前最新版本 }
2. 在Activity销毁时完整清理WebView资源
在WebViewActivity的onDestroy方法中,按顺序执行以下操作,确保释放所有关联引用:
@Override protected void onDestroy() { if (webView != null) { // 先从父布局移除WebView,避免父容器持有引用 ViewParent parent = webView.getParent(); if (parent != null) { ((ViewGroup) parent).removeView(webView); } // 停止加载并清理WebView内部资源 webView.stopLoading(); webView.getSettings().setJavaScriptEnabled(false); webView.clearHistory(); webView.clearCache(true); webView.removeAllViews(); // 销毁WebView并置空引用 webView.destroy(); webView = null; } super.onDestroy(); }
3. 尝试用Application Context初始化WebView(可选)
如果上述步骤仍无法解决泄漏,可以尝试用Application Context创建WebView,避免WebView持有Activity的强引用:
webView = new WebView(getApplicationContext()); // 后续添加到布局的逻辑保持不变
注意:这种方式可能导致部分WebView功能异常(如弹窗、权限请求),需要测试验证后再使用。
4. 验证泄漏修复结果
重新运行App,触发Activity销毁流程,通过LeakCanary再次检测,确认内存泄漏是否消失。
内容的提问来源于stack exchange,提问作者user3610389
相关产品推荐
相关产品推荐

