maplibre / maplibre/maplibre-plugins-android
[Bug] Memory Leak in DraggableAnnotationController with MapView
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 50
- Forks
- 33
- PR merge metrics
- No merged PRs in 30d
Description
Summary
Using LeakCanary, I detected a memory leak involving the DraggableAnnotationController and MapView classes. The leak is observed when an Android activity (e.g., HomeActivity) is destroyed, but the View's context holds a reference to the destroyed activity, causing retained objects in memory.
LeakCanary Trace:
GC Root: Thread object
│
├─ android.net.ConnectivityThread instance
│ Leaking: NO (PathClassLoader↓ is not leaking)
│ Thread name: 'ConnectivityThread'
│ ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│ Leaking: NO (DraggableAnnotationController↓ is not leaking and A
│ ClassLoader is never leaking)
│ ↓ ClassLoader.runtimeInternalObjects
├─ java. lang.Object[] array
│ Leaking: NO (DraggableAnnotationController↓ is not leaking)
│ ↓ Object[42461]
├─ org.maplibre.android.plugins.annotation.DraggableAnnotationController class
│ Leaking: NO (a class is never leaking)
│ ↓ static DraggableAnnotationController. INSTANCE
│ ~~~~~~~~
├─ org.maplibre.android.plugins.annotation.DraggableAnnotationController
│ instance
│ Leaking: UNKNOWN
│ Retaining 25,9 kB in 798 objects
│ ↓ DraggableAnnotationController.mapView
│ ~~~~~~~
├─ org.maplibre.android.maps.MapView instance
│ Leaking: YES (View.mContext references a destroyed activity)
│ Retaining 7,7 kB in 130 objects
│ View not part of a window view hierarchy
│ View.mAttachInfo is null (view detached)
│ View.mWindowAttachCount = 1
│ mContext instance of com.x.x.home.view.HomeActivity with
│ mDestroyed = true
│ ↓ View.mContext
╰→ com.x.x.home.view.HomeActivity instance
Leaking: YES (ObjectWatcher was watching this because com.x.x.
home.view.HomeActivity received Activity#onDestroy() callback and
Activity#mDestroyed is true)
Retaining 109,0 kB in 4122 objects
key = e360c6bd-48ce-4be6-9684-4ef785125e60
watchDurationMillis = 5658
retainedDurationMillis = 657
mApplication instance of com.x.x.x
mBase instance of com.x.x.x.wrapper.PrefsContextWrapper
Steps to Reproduce
- Use MapLibre Android and instantiate a
DraggableAnnotationControlleron aMapView. - Destroy the associated activity (e.g., navigate away or close the screen).
- Use LeakCanary to observe memory leaks.
Expected Behavior
No references to destroyed Activity should be held; all resources should be released and garbage collected.
Actual Behavior
MapViewretains a reference to a destroyed context (Activity).- Objects related to
DraggableAnnotationControllerandMapVieware not properly cleaned up, resulting in a memory leak.
Environment:
- Repository: maplibre/maplibre-plugins-android
- Companion app: com.x.x
- LeakCanary results from real device
Tactical Fix
At the moment i fix the issue by clearing the instance via reflection. This is a shortcut for the fix.
Strategic Fix
However looking at the codebase, would be preferable each layers e.g SymbolLayer have the ability to clear the instance when the Layer tearDown. (will raise the PR)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with DraggableAnnotationController and MapView, then inspect how SymbolLayer teardown is handled. Reproduce the activity-destruction scenario with LeakCanary and trace the controller's retained MapView reference. Done means destroyed activities and their MapView instances are no longer retained after layer teardown.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, java
- Domain
- mobile, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100