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();
}
我对这个场景比较陌生,没有什么编程背景,所以如果我问了一些愚蠢的问题,我提前道歉。 我正在使用 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();
}