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
Mapbox Version
11.20.1 (default)
React Native Version
0.81.5
Platform
Android
@rnmapbox/mapsversion10.3.1
Standalone component to reproduce
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:
Observed behavior and steps to reproduce
Every mount/unmount cycle of a
MapViewcontaining aLocationPuckpermanently leaks oneFusedLocationProviderClient(visible as afusedLocationCl…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 meminfobetween windows:fusedLocationCl…threadsMapboxRenderThreadControl: 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 theLocationPuck) releases the location component's provider: the fused-location client count stays constant across mount/unmount cycles, matching the (correct) behavior ofMapboxRenderThread.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
dumpsys meminfoacross fixed navigation-cycle windows) applied to another map engine, for comparison of failure signatures: [expo-maps] possible memory leak or navigation issue. expo/expo#41648