react-native-background-geolocation: [Android] Infinite geofencing - Out of memory when trying to add geofences

Hi,

When trying to activate geofencing for about 20.000 geofences, we’re ending up with an “Unable to create protected region in stack for implicit overflow check. Reason: Out of memory size: 4096”-error on Android. On iOS, it’s working fine and as expected.

Tested on multiple physical Android devices with non-metro builds. On my Nokia 7.1 with Android 10, the app breaks after 8.000 geofences. On my OnePlus Nord N100, it stops after 14.000 geofences.

The docs mention infinite Geofencing.

The Background Geolocation SDK contains unique and powerful Geofencing features that allow you to monitor any number of circular geofences you wish (thousands even), in spite of limits imposed by the native platform APIs (20 for iOS; 100 for Android).

Unfortunately, it’s not infinite as we’re reaching memory limits. We bought the react-native-background-geolocation because we wanted to be able to set infinite geofences.

We’re using following Geofence-object: return { identifier: 'Geofence_${i}', longitude: s.latitude, latitude: s.longitude, notifyOnEntry: true, notifyOnDwell: false, notifyOnExit: true, radius: 200, }

Your Environment

  • Plugin version: 4.4.4
  • Platform: Android
  • OS version: 10/11
  • Device manufacturer / model: Nokia 7.1 / OnePlus Nord N100
  • React Native version (react-native -v): 0.64.2
  • Plugin config
All defaults

Expected Behavior

We should be able to add our 20.000 geofences in a performant way as in our iOS-app.

Actual Behavior

App freezes and becomes unusable.

Steps to Reproduce

  1. Install react-native-background-geolocation
  2. Call BackgroundGeolocation.addGeofences([...]) with an array of ±20.000 geofences. You don’t have to start geofencing, it breaks when trying to add geofences.
  3. adb logcat and watch the geofences being added
  4. Depending on your device, OutOfMemory-exceptions will occur.

Debug logs

Logs
...
02-04 13:13:51.517 17003 17389 I TSLocationManager:   ✅  Geofence_8110
02-04 13:13:51.520 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.520 17003 17389 I TSLocationManager:   ✅  Geofence_8111
02-04 13:13:51.522 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.522 17003 17389 I TSLocationManager:   ✅  Geofence_8112
02-04 13:13:51.525 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.525 17003 17389 I TSLocationManager:   ✅  Geofence_8113
02-04 13:13:51.527 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.527 17003 17389 I TSLocationManager:   ✅  Geofence_8114
02-04 13:13:51.529 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.529 17003 17389 I TSLocationManager:   ✅  Geofence_8115
02-04 13:13:51.531 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.531 17003 17389 I TSLocationManager:   ✅  Geofence_8116
02-04 13:13:51.534 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.534 17003 17389 I TSLocationManager:   ✅  Geofence_8117
02-04 13:13:51.536 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.536 17003 17389 I TSLocationManager:   ✅  Geofence_8118
02-04 13:13:51.538 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.538 17003 17389 I TSLocationManager:   ✅  Geofence_8119
02-04 13:13:51.542 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.542 17003 17389 I TSLocationManager:   ✅  Geofence_8120
02-04 13:13:51.545 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.545 17003 17389 I TSLocationManager:   ✅  Geofence_8121
02-04 13:13:51.570 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.570 17003 17389 I TSLocationManager:   ✅  Geofence_8122
02-04 13:13:51.572 17003 17389 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 13:13:51.572 17003 17389 I TSLocationManager:   ✅  Geofence_8123
02-04 13:13:51.573 17003 24007 F app.package.name: thread.cc:4101] Unable to create protected region in stack for implicit overflow check. Reason: Out of memory size:  4096

I’ve also tried to add the geofences in chunks of 1.000 geofences, ending up with following logs (on the same device as above):

Logs
...
02-04 14:07:10.506 21994 28965 I TSLocationManager:   ✅  Geofence_8567
02-04 14:07:10.508 21994 28965 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 14:07:10.508 21994 28965 I TSLocationManager:   ✅  Geofence_8568
02-04 14:07:10.510 21994 28965 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 14:07:10.510 21994 28965 I TSLocationManager:   ✅  Geofence_8569
02-04 14:07:10.512 21994 28965 I TSLocationManager: [c.t.l.data.sqlite.GeofenceDAO create]
02-04 14:07:10.512 21994 28965 I TSLocationManager:   ✅  Geofence_8570
02-04 14:07:10.513 21994 28965 W libc    : pthread_create failed: couldn't mprotect R+W 1077248-byte thread mapping region: Out of memory
02-04 14:07:10.513 21994 28965 W package.name: Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Try again" (VmSize 134650104 kB)
02-04 14:07:10.514 21994 28965 W libc    : pthread_create failed: couldn't mprotect R+W 1077248-byte thread mapping region: Out of memory
02-04 14:07:10.514 21994 28965 W package.name: Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Try again" (VmSize 134650104 kB)
02-04 14:07:10.515 21994 28148 W libc    : pthread_create failed: couldn't mprotect R+W 1077248-byte thread mapping region: Out of memory
02-04 14:07:10.515 21994 28148 W package.name: Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Try again" (VmSize 134650104 kB)
02-04 14:07:10.516 21994 28148 W libc    : pthread_create failed: couldn't mprotect R+W 1077248-byte thread mapping region: Out of memory
02-04 14:07:10.516 21994 28148 W package.name: Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Try again" (VmSize 134650104 kB)
02-04 14:07:10.524 21994 28965 E AndroidRuntime: FATAL EXCEPTION: AsyncTask #10
02-04 14:07:10.524 21994 28965 E AndroidRuntime: Process: com.package.name, PID: 21994
02-04 14:07:10.524 21994 28965 E AndroidRuntime: java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
02-04 14:07:10.524 21994 28965 E AndroidRuntime: 	at java.lang.Thread.nativeCreate(Native Method)
02-04 14:07:10.524 21994 28965 E AndroidRuntime: 	at java.lang.Thread.start(Thread.java:883)
02-04 14:07:10.524 21994 28965 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:975)
02-04 14:07:10.524 21994 28965 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:1043)
02-04 14:07:10.524 21994 28965 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1185)
02-04 14:07:10.524 21994 28965 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
02-04 14:07:10.524 21994 28965 E AndroidRuntime: 	at java.lang.Thread.run(Thread.java:919)
02-04 14:07:10.524 21994 28148 E AndroidRuntime: FATAL EXCEPTION: AsyncTask #9
02-04 14:07:10.524 21994 28148 E AndroidRuntime: Process: com.package.name, PID: 21994
02-04 14:07:10.524 21994 28148 E AndroidRuntime: java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
02-04 14:07:10.524 21994 28148 E AndroidRuntime: 	at java.lang.Thread.nativeCreate(Native Method)
02-04 14:07:10.524 21994 28148 E AndroidRuntime: 	at java.lang.Thread.start(Thread.java:883)
02-04 14:07:10.524 21994 28148 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:975)
02-04 14:07:10.524 21994 28148 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:1043)
02-04 14:07:10.524 21994 28148 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1185)
02-04 14:07:10.524 21994 28148 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
02-04 14:07:10.524 21994 28148 E AndroidRuntime: 	at java.lang.Thread.run(Thread.java:919)
02-04 14:07:10.548 21994 28148 E TSLocationManager: [c.t.l.a.BackgroundGeolocation$x0 uncaughtException]
02-04 14:07:10.548 21994 28148 E TSLocationManager:   ‼️  Uncaught Exception: pthread_create (1040KB stack) failed: Try again
02-04 14:07:10.548 21994 28148 E TSLocationManager: {"activityRecognitionInterval":10000,"allowIdenticalLocations":false,"authorization":{},"autoSync":true,"autoSyncThreshold":0,"backgroundPermissionRationale":{"title":"Allow {applicationName} to access this device's location even when closed or not in use?","message":"[CHANGEME] This app collects location data for FEATURE X and FEATURE Y.","positiveAction":"Change to \"{backgroundPermissionOptionLabel}\"","negativeAction":""},"batchSync":false,"configUrl":"","debug":false,"deferTime":0,"desiredAccuracy":0,"desiredOdometerAccuracy":100,"disableAutoSyncOnCellular":false,"disableElasticity":false,"disableLocationAuthorizationAlert":false,"disableMotionActivityUpdates":false,"disableStopDetection":false,"distanceFilter":10,"elasticityMultiplier":1,"enableHeadless":false,"enableTimestampMeta":false,"extras":{},"fastestLocationUpdateInterval":-1,"foregroundService":true,"geofenceInitialTriggerEntry":true,"geofenceModeHighAccuracy":false,"geofenceProximityRadius":1000,"geofenceTemplate":"","headers":{},"headlessJobService":"com.transistorsoft.rnbackgroundgeolocation.HeadlessTask","heartbeatInterval":-1,"httpRootProperty":"location","httpTimeout":60000,"isMoving":false,"locationAuthorizationRequest":"Always","locationTemplate":"","locationTimeout":60,"locationUpdateInterval":1000,"locationsOrderDirection":"ASC","logLevel":0,"logMaxDays":3,"maxBatchSize":-1,"maxDaysToPersist":1,"maxRecordsToPersist":-1,"method":"POST","minimumActivityRecognitionConfidence":75,"motionTriggerDelay":0,"notification":{"layout":"","title":"","text":"Location Service activated","color":"","channelName":"TSLocationManager","smallIcon":"","largeIcon":"","priority":0,"sticky":false,"strings":{},"actions":[]},"params":{},"persist":true,"persistMode":2,"schedule":[],"scheduleUseAlarmManager":false,"speedJumpFilter":300,"startOnBoot":false,"stationaryRadius":25,"stopAfterElapsedMinutes":0,"stopOnStationary":false,"stopOnTerminate":true,"stopTimeout":5,"triggerActivities":"in_vehicle, on_bicycle, on_foot, running, walking","url":"","useSignificantChangesOnly":false,"enabled":false,"schedulerEnabled":false,"trackingMode":1,"odometer":0,"isFirstBoot":false,"didLaunchInBackground":false,"didDeviceReboot":false}
02-04 14:07:10.548 21994 28148 E TSLocationManager: java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
02-04 14:07:10.548 21994 28148 E TSLocationManager: 	at java.lang.Thread.nativeCreate(Native Method)
02-04 14:07:10.548 21994 28148 E TSLocationManager: 	at java.lang.Thread.start(Thread.java:883)
02-04 14:07:10.548 21994 28148 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:975)
02-04 14:07:10.548 21994 28148 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:1043)
02-04 14:07:10.548 21994 28148 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1185)
02-04 14:07:10.548 21994 28148 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
02-04 14:07:10.548 21994 28148 E TSLocationManager: 	at java.lang.Thread.run(Thread.java:919)
02-04 14:07:10.548 21994 28965 E TSLocationManager: [c.t.l.a.BackgroundGeolocation$x0 uncaughtException]
02-04 14:07:10.548 21994 28965 E TSLocationManager:   ‼️  Uncaught Exception: pthread_create (1040KB stack) failed: Try again
02-04 14:07:10.548 21994 28965 E TSLocationManager: {"activityRecognitionInterval":10000,"allowIdenticalLocations":false,"authorization":{},"autoSync":true,"autoSyncThreshold":0,"backgroundPermissionRationale":{"title":"Allow {applicationName} to access this device's location even when closed or not in use?","message":"[CHANGEME] This app collects location data for FEATURE X and FEATURE Y.","positiveAction":"Change to \"{backgroundPermissionOptionLabel}\"","negativeAction":""},"batchSync":false,"configUrl":"","debug":false,"deferTime":0,"desiredAccuracy":0,"desiredOdometerAccuracy":100,"disableAutoSyncOnCellular":false,"disableElasticity":false,"disableLocationAuthorizationAlert":false,"disableMotionActivityUpdates":false,"disableStopDetection":false,"distanceFilter":10,"elasticityMultiplier":1,"enableHeadless":false,"enableTimestampMeta":false,"extras":{},"fastestLocationUpdateInterval":-1,"foregroundService":true,"geofenceInitialTriggerEntry":true,"geofenceModeHighAccuracy":false,"geofenceProximityRadius":1000,"geofenceTemplate":"","headers":{},"headlessJobService":"com.transistorsoft.rnbackgroundgeolocation.HeadlessTask","heartbeatInterval":-1,"httpRootProperty":"location","httpTimeout":60000,"isMoving":false,"locationAuthorizationRequest":"Always","locationTemplate":"","locationTimeout":60,"locationUpdateInterval":1000,"locationsOrderDirection":"ASC","logLevel":0,"logMaxDays":3,"maxBatchSize":-1,"maxDaysToPersist":1,"maxRecordsToPersist":-1,"method":"POST","minimumActivityRecognitionConfidence":75,"motionTriggerDelay":0,"notification":{"layout":"","title":"","text":"Location Service activated","color":"","channelName":"TSLocationManager","smallIcon":"","largeIcon":"","priority":0,"sticky":false,"strings":{},"actions":[]},"params":{},"persist":true,"persistMode":2,"schedule":[],"scheduleUseAlarmManager":false,"speedJumpFilter":300,"startOnBoot":false,"stationaryRadius":25,"stopAfterElapsedMinutes":0,"stopOnStationary":false,"stopOnTerminate":true,"stopTimeout":5,"triggerActivities":"in_vehicle, on_bicycle, on_foot, running, walking","url":"","useSignificantChangesOnly":false,"enabled":false,"schedulerEnabled":false,"trackingMode":1,"odometer":0,"isFirstBoot":false,"didLaunchInBackground":false,"didDeviceReboot":false}
02-04 14:07:10.548 21994 28965 E TSLocationManager: java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
02-04 14:07:10.548 21994 28965 E TSLocationManager: 	at java.lang.Thread.nativeCreate(Native Method)
02-04 14:07:10.548 21994 28965 E TSLocationManager: 	at java.lang.Thread.start(Thread.java:883)
02-04 14:07:10.548 21994 28965 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:975)
02-04 14:07:10.548 21994 28965 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:1043)
02-04 14:07:10.548 21994 28965 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1185)
02-04 14:07:10.548 21994 28965 E TSLocationManager: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
02-04 14:07:10.548 21994 28965 E TSLocationManager: 	at java.lang.Thread.run(Thread.java:919)
02-04 14:07:10.550 21994 28148 W libc    : pthread_create failed: couldn't mprotect R+W 1077248-byte thread mapping region: Out of memory

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 17 (12 by maintainers)

Most upvoted comments

I wonder if that’s a requirement for other performance edge cases too

I don’t think so. Performing thousands of SQLite inserts in a single task is a pretty rare case.

When the plugin’s actually doing work tracking, it would only be doing something once / second (in the most aggressive configuration with distanceFilter: 0. In more typical cases with a higher distanceFilter, the plugin might perform work only every 5 or 10s.

but as part of your sweep to fix the strict mode violations you implemented the multi-thread buffering between log queue

I think that was only for during the first milliseconds of the app booting, where the plugin constructs a “LoggerFacade” to intercept initial logger messages in-memory while the database gets initialized in a background-thread. After the x milliseconds it takes to for the db to init, the in-memory records are INSERTed and the LoggerFacade thrown away.

I’ll certainly be having a closer look and refreshing my memory on the path a log-entry takes.

Ok, it crashed after about 2000 records on Nexus 5 @ 6.0.1 and ~4000 records on Pixel 3a @ 12 so clearly something is wrong.

I tried a few things then finally simply removed the command to log the insert (the plugin’s logger does SQLite inserts too) and that fixes it. In my test I simply changed the log output to used Android’s standard logger Log.d, bypassing the plugin’s logger logback-android

20000 inserts is successful on both old and new devices.

.
.
.
02-07 16:36:41.433 20693 20750 D TSLocationManager:   ✅  Test: 19999

However, I highly recommend that you insert only a subset of your geofences based upon the city the device currently exists. You’ll get much better performance.