Minimum-viable reproduction for a JNI global reference leak in
react-native-vision-camera v5 on Android.
Related upstream issues:
After several minutes with the camera attached, the process aborts with:
JNI ERROR (app bug): global reference table overflow (max=51200)
... ~50,300 of com.margelo.nitro.camera.HybridFrameSpec$CxxPart
The frame processor body is intentionally empty — just frame.dispose().
This rules out user code as the cause: simply attaching a frame output to
the camera at 30+ fps is sufficient.
With heavier worklet workloads, the same root cause manifests as an ART
SuspendAll timeout SIGABRT on the camera frame thread instead — both
crashes are downstream of the same JHybridObject::CxxPart ↔ Java
HybridObject$CxxPart strong-reference cycle.
react-native-vision-camera ^5.0.9
react-native-vision-camera-worklets ^5.0.9
react-native-worklets ^0.8.3
react-native-reanimated ~4.1.1
react-native-nitro-modules ^0.35.6
react-native 0.81.5
expo ~54.0.33
npm install
npx expo prebuild --clean
npx expo run:android # or --device <serial>Grant the camera permission, leave the app open on the camera view, and wait. Expected time-to-crash by camera FPS:
| Camera FPS | Time-to-crash |
|---|---|
| 120 | ~7 min |
| 60 | ~14 min |
| 30 | ~28 min |
The relationship is linear-inverse-proportional: roughly 1 leaked JNI global ref per camera frame, regardless of FPS or what's in the FP body.
The FPS in App.tsx is set to 120 by default. Lower it for a slower repro.
In adb logcat, watch for:
F libc : Fatal signal 6 (SIGABRT)
F DEBUG : Abort message: 'JNI ERROR (app bug): global reference table overflow ...'
F DEBUG : ##### of com.margelo.nitro.camera.HybridFrameSpec$CxxPart
To watch memory grow before the crash, every minute or so:
adb shell dumpsys meminfo com.vision-camera-leak | grep -E "Other \(malloced\)"The Other (malloced) count grows linearly with frames processed. At
120fps you should see roughly +14,000 allocations per minute.
Reported on:
- Pixel devices (Android 13-16)
- Samsung A12, Samsung tablet (per upstream issue #3879)
- OnePlus Nord CE4 Android 16 (per upstream issue #3824)
Both dev and release builds are affected. Build mode only changes time-to-crash by a small factor (release is slightly slower due to better Hermes / GC efficiency, but the bug fundamentally happens regardless).
These linearly extend time-to-crash but don't prevent it:
- Cooldown after each FP body: forces the camera frame thread idle briefly between dispatches → more time for GC to reclaim Frame objects.
- Reduce per-frame SharedValue reads: each
sv.valueaccess is a worklet-runtime mutex cycle; fewer reads = less Runnable pressure. - Lower the camera FPS: directly halves the leak rate.
None of these break the JHybridObject::CxxPart reference cycle. The
real fix has to come from react-native-nitro-modules itself.