rnmapbox / rnmapbox/maps

[Bug]: LocationPuck leaks one fused-location provider (thread + native memory) per MapView destroy on Android

Open
#4,225 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Kotlin
Stars
2.9k
Forks
947
Avg merge
6d 37m
Merged PRs (30d)
1

Description

Mapbox Version

11.20.1 (default)

React Native Version

0.81.5

Platform

Android

@rnmapbox/maps version

10.3.1

Standalone component to reproduce
import React, { useEffect, useState } from 'react';
import { MapView, Camera, LocationPuck } from '@rnmapbox/maps';

const REMOUNT_INTERVAL_MS = 3000;

function BugReportExample() {
  const [mapVisible, setMapVisible] = useState(true);

  // Simulates navigating to and from a screen containing a map:
  // each cycle mounts a fresh MapView + LocationPuck, then unmounts it.
  useEffect(() => {
    const interval = setInterval(() => {
      setMapVisible((visible) => !visible);
    }, REMOUNT_INTERVAL_MS);
    return () => clearInterval(interval);
  }, []);

  if (!mapVisible) {
    return null;
  }

  return (
    <MapView style={{ flex: 1 }}>
      <Camera centerCoordinate={[-74.00597, 40.71427]} zoomLevel={14} />
      <LocationPuck />
    </MapView>
  );
}

Location permission must be granted (the puck's location provider is only created once permissions allow it). While the component remounts, count the Play Services fused-location handler threads:

PID=$(adb shell pidof <your.package>)
adb shell "for t in /proc/$PID/task/*/comm; do cat \$t; done" | grep -c fusedLocation
Observed behavior and steps to reproduce

Every mount/unmount cycle of a MapView containing a LocationPuck permanently leaks one FusedLocationProviderClient (visible as a fusedLocationCl… handler thread) plus its native allocations.

Measured in a production app (Expo SDK 54, new architecture, release build, no expo-dev-client), repeatedly opening and backing out of a screen containing a map — exactly 10 navigation cycles per measurement window, thread census + dumpsys meminfo between windows:

Baseline (1 live map) After 10 open/back cycles After 20
fusedLocationCl… threads 3 13 23 (+1 per mount)
MapboxRenderThread 1 1 1 (map teardown itself is clean)

Control: removing only <LocationPuck /> from the same screen and repeating the identical 30-cycle protocol keeps the fused-location thread count constant at 1 and removes the linear component of native-heap growth. The render thread and Java heap are clean in both configurations — the leak is specific to the puck's location provider.

Device: Samsung SM-P613, Android 14 (API 34), Google Play Services 26.19.34.

Expected behavior

Destroying a MapView (or unmounting the LocationPuck) releases the location component's provider: the fused-location client count stays constant across mount/unmount cycles, matching the (correct) behavior of MapboxRenderThread.

Notes / preliminary analysis

The leak is Android-specific in our testing and isolates cleanly to LocationPuck: the identical navigation protocol with the puck removed (and nothing else changed) keeps the fused-location client count constant.

Additional links and references
  • The same measurement methodology (thread census + dumpsys meminfo across fixed navigation-cycle windows) applied to another map engine, for comparison of failure signatures: expo/expo#41648

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

Reproduce the remount cycle with MapView and LocationPuck after granting location permission, then run the provided adb fusedLocation thread census and dumpsys meminfo measurements. Trace the Android LocationPuck location-provider lifecycle across MapView destruction and unmounting. Done means repeated cycles no longer increase fused-location threads or native memory, while the render thread remains clean.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, javascript, kotlin, react-native
Domain
mobile, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.