LeakCanary 在我的 Java Android 应用程序中检测到泄漏 - Google 地图

LeakCanary detecting a leak in my Java Android app - Google Maps

我对这个场景比较陌生,没有什么编程背景,所以如果我问了一些愚蠢的问题,我提前道歉。 我正在使用 SupportMapFragment 显示 google 地图。我这样做是为了防止 onDestroyView() 中的泄漏,但是不知道这是对还是错?

@Override
protected void onDestroy() {
    super.onDestroy();
    mMap.clear();
    mapView.onDestroy();
}

完整代码在这里:

https://github.com/warfo09/warforepo/blob/main/MainActivity.java

这是我退出应用程序时得到的结果:

  │ GC Root: Local variable in native code
  │
  ├─ com.google.maps.api.android.lib6.gmm6.vector.n instance
  │    Leaking: UNKNOWN
  │    Retaining 1391172 bytes in 9076 objects
  │    Thread name: 'RenderDrive'
  │    ↓ n.e
  │        ~
  ├─ com.google.maps.api.android.lib6.gmm6.vector.p instance
  │    Leaking: UNKNOWN
  │    Retaining 1391005 bytes in 9073 objects
  │    ↓ p.k
  │        ~
  ├─ com.google.maps.api.android.lib6.gmm6.api.ac instance
  │    Leaking: UNKNOWN
  │    Retaining 1390953 bytes in 9072 objects
  │    View not part of a window view hierarchy
  │    View.mAttachInfo is null (view detached)
  │    View.mWindowAttachCount = 1
  │    mContext instance of android.app.Application
  │    ↓ ac.mParent
  │         ~~~~~~~
  ├─ android.widget.FrameLayout instance
  │    Leaking: UNKNOWN
  │    Retaining 405651 bytes in 5497 objects
  │    View not part of a window view hierarchy
  │    View.mAttachInfo is null (view detached)
  │    View.mWindowAttachCount = 1
  │    mContext instance of android.app.Application
  │    ↓ FrameLayout.mParent
  │                  ~~~~~~~
  ├─ com.google.android.gms.maps.MapView instance
  │    Leaking: YES (View.mContext references a destroyed activity)
  │    Retaining 403455 bytes in 5482 objects
  │    View not part of a window view hierarchy
  │    View.mAttachInfo is null (view detached)
  │    View.mID = R.id.mapsView
  │    View.mWindowAttachCount = 1
  │    mContext instance of com.app.trikojis.MainActivity with mDestroyed = true
  │    ↓ MapView.mContext
  ╰→ com.app.trikojis.MainActivity instance
  ​     Leaking: YES (ObjectWatcher was watching this because com.app.trikojis.MainActivity received Activity#onDestroy()
  ​     callback and Activity#mDestroyed is true)
  ​     Retaining 60455 bytes in 956 objects
  ​     key = f3613896-cce8-4aac-a73a-d4a79700c719
  ​     watchDurationMillis = 56451
  ​     retainedDurationMillis = 51448
  ​     mApplication instance of android.app.Application
  ​     mBase instance of androidx.appcompat.view.ContextThemeWrapper, not wrapping known Android context
  
  METADATA
  
  Build.VERSION.SDK_INT: 28
  Build.MANUFACTURER: samsung
  LeakCanary version: 2.5
  App process name: com.app.trikojis
  Stats: LruCache[maxSize=3000,hits=5749,misses=110455,hitRate=4%]
  RandomAccess[bytes=5714581,reads=110455,travel=48839777691,range=35924253,size=41590935]
  Analysis duration: 11845 ms```



   

leaktrace 表明 MainActivity 已被销毁但由 MapView 保存在内存中,MapView 将 activity 作为其上下文。

现在,真正奇怪的是 MapView 是 FrameLayout 的父级,该 FrameLayout 以 Application 作为其上下文,它本身是一个名为 'ac'(混淆名称)的视图的父级,它被保存通过“RenderDrive”线程实例的字段。

这绝对是 Google 地图库中的错误。你应该在他们的错误跟踪器上报告这个问题,也可以随意使用我刚刚发布的这个答案。

我不知道究竟是什么错误导致了此泄漏,但您可以通过在 activity 被销毁时删除 MapView 的所有子项来修复它。

@Override
protected void onDestroy() {
    super.onDestroy();
    mMap.clear();
    mapView.onDestroy();
    mapView.removeAllViews();
}