I got LocationManager instance by getSystemSercice(LOCATION_SERVICE) of activity, After a few minutes leak canary detect memory leaks:
┬───
│ 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```
My earlier answer was incorrect, as I was assuming ContextImpl had a different lifecycle as the activity that has it as a base context. Turns out they have the same lifecycle (comment here: https://issuetracker.google.com/issues/159308651#comment6)
What that means for this particular issue is that the leak is elsewhere. Reading through the source and leak trace:
LocationManager
has an mContext
field that points to a ContextImpl that references an activity. That means LocationManager
's lifecycle should be the same as the one of the activity.LocationManager$ListenerTransport
which is a binder held by native memory, used to allow another process to call back into this process. Until the other process let go of the reference to the binder on its side, the binder can't be GCed on the app side. This is a classic AOSP leak, and the fix should be either for LocationManager to an app context, or for LocationManager$ListenerTransport to let go of its ref to its outer class (ie make it a static class with nullable ref) when the activity is destroyed.That's all in AOSP though. In your app, can you try calling getSystemSercice(LOCATION_SERVICE)
on the app context instead of the activity context? ie in your activity instead of this.getSystemSercice(LOCATION_SERVICE);
try this.getApplication().getSystemSercice(LOCATION_SERVICE);
.
Edit: or it could be that the activity code isn't calling locationManager.removeUpdates(this);