maplibre / maplibre/maplibre-plugins-android

[Bug] Memory Leak in DraggableAnnotationController with MapView

Open
#88 1 comment 0 reactions 0 assignees View on GitHub

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

  1. Use MapLibre Android and instantiate a DraggableAnnotationController on a MapView.
  2. Destroy the associated activity (e.g., navigate away or close the screen).
  3. 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

  • MapView retains a reference to a destroyed context (Activity).
  • Objects related to DraggableAnnotationController and MapView are 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.