安卓定位管理器内存泄漏

3

我通过使用activity的getSystemService(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```

当你不再需要locationManager时,请尝试使用locationManager.removeUpdates(this); - S T
@user6915871,您能确认您是否调用了removeUpdates吗?您可以分享一下活动代码吗? - Pierre-Yves Ricau
https://dev.to/pyricau/beware-packagemanager-leaks-223g - ecle
1个回答

4
我的早期答案是错误的,因为我假设ContextImpl具有不同的生命周期,作为具有它作为基础上下文的活动。结果发现它们具有相同的生命周期(在此处评论: https://issuetracker.google.com/issues/159308651#comment6)
对于这个特定问题,这意味着泄漏发生在其他地方。通过阅读源代码和泄漏跟踪:
- LocationManager拥有一个mContext字段,指向引用活动的ContextImpl。这意味着LocationManager的生命周期应该与该活动的生命周期相同。 - 然而,它被LocationManager$ListenerTransport所持有,后者是由本机内存持有的绑定器,用于允许另一个进程回调到该进程。直到另一个进程在其端放弃对绑定器的引用,该绑定器才不能在应用程序侧进行垃圾回收。这是一个经典的AOSP泄漏,修复方法应该是将LocationManager更改为应用程序上下文,或者当活动销毁时,使LocationManager $ListenerTransport释放对其外部类的引用(即使其成为可为空的静态类)。
不过,这都是在AOSP中。在您的应用程序中,您可以尝试在应用程序上下文而不是活动上下文中调用getSystemService(LOCATION_SERVICE)吗?也就是说,在您的活动中,尝试使用this.getApplication().getSystemService(LOCATION_SERVICE);而不是this.getSystemService(LOCATION_SERVICE);
编辑:或者可能是因为活动代码没有调用locationManager.removeUpdates(this);

getApplicationContext() 是解决方案。谢谢。 - anatoli
@anatoli 仍然有泄漏,尝试使用getApplication()、getApplicationContext()和removeUpdates(this)进行调用。 - Igor M.
https://dev.to/pyricau/beware-packagemanager-leaks-223g - ecle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接