我通过 Activity 的 getSystemSercice(LOCATION_SERVICE) 获得了 LocationManager 实例,几分钟后 leak canary 检测到内存泄漏:
┬───
│ GC Root: Global variable in native code
│
├─ android.location.LocationManager$ListenerTransport instance
│ Leaking: UNKNOWN
│ ↓ LocationManager$ListenerTransport.this$0
│ ~~~~~~
├─ android.location.LocationManager instance
│ Leaking: UNKNOWN
│ ↓ LocationManager.mContext
│ ~~~~~~~~
├─ android.app.ContextImpl instance
│ Leaking: UNKNOWN
│ ↓ ContextImpl.mAutofillClient
│ ~~~~~~~~~~~~~~~
╰→ com....manager.MapsActivity instance
Leaking: YES (ObjectWatcher was watching this because com...manager.live2.MapsActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
key = 3e8186a7-b057-4c0a-aca2-b0fc4257bb11
watchDurationMillis = 107841
retainedDurationMillis = 102829
METADATA
Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: Xiaomi
LeakCanary version: 2.3
App process name: com...
Analysis duration: 9763 ms```
最佳答案
我之前的回答是错误的,因为我假设 ContextImpl 与将它作为基础上下文的 Activity 具有不同的生命周期。原来他们有相同的生命周期(在这里评论:https://issuetracker.google.com/issues/159308651#comment6)
对于此特定问题,这意味着泄漏在其他地方。阅读源代码和泄漏跟踪:
LocationManager
有一个mContext
字段指向引用 Activity 的 ContextImpl。这意味着LocationManager
的生命周期应该与 Activity 之一相同。- 但是,它由
LocationManager$ListenerTransport
保存在内存中,LocationManager$ListenerTransport
是 native 内存保存的绑定(bind)器,用于允许另一个进程回调此进程。直到另一个进程在其一侧释放对 Binder 的引用, Binder 才能在应用程序端被 GC。这是一个典型的 AOSP 泄漏,修复应该是 LocationManager 到应用程序上下文,或者 LocationManager$ListenerTransport 在 Activity销毁。
不过,这就是 AOSP 中的全部内容。在您的应用程序中,您可以尝试在应用程序上下文而不是 Activity 上下文中调用 getSystemSercice(LOCATION_SERVICE)
吗?即在您的 Activity 中而不是 this.getSystemSercice(LOCATION_SERVICE);
尝试 this.getApplication().getSystemSercice(LOCATION_SERVICE);
。
编辑:或者可能是 Activity 代码未调用 locationManager.removeUpdates(this);
关于Android LocationManager 泄漏内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62551090/