Summary
_AndroidReplayHandler (the isolate-side replay screenshot handler) leaks JNI object references in three places.
Details
1. Bitmap$Config.ARGB_8888 leaks on every bitmap creation
https://github.com/getsentry/sentry-dart/blob/a7f011a3/packages/flutter/lib/src/native/java/android_replay_recorder.dart#L134
_bitmap ??= native.Bitmap.createBitmap$10(
item.width, item.height, native.Bitmap$Config.ARGB_8888);
Bitmap$Config.ARGB_8888 is a static getter that returns a new JNI reference each call (the generated binding comments say "must be released after use"). This reference is passed to createBitmap$10 and then abandoned — it leaks every time a new bitmap is created (first capture, and on every dimension change).
2. _bitmap never released on isolate shutdown
https://github.com/getsentry/sentry-dart/blob/a7f011a3/packages/flutter/lib/src/native/java/android_replay_recorder.dart#L98
The cached Bitmap is released when dimensions change (line 126), but when the worker isolate shuts down the bitmap is abandoned without releasing.
3. _nativeReplay never released on isolate shutdown
https://github.com/getsentry/sentry-dart/blob/a7f011a3/packages/flutter/lib/src/native/java/android_replay_recorder.dart#L99-L103
The ReplayIntegration JObject obtained in the constructor is stored as a field but never released.
Root cause
WorkerHandler has no close() lifecycle callback. When the isolate receives the shutdown command, it closes the ReceivePort without giving the handler a chance to release resources.
Suggested fix
- Add a
FutureOr<void> close() method to WorkerHandler (default no-op)
- Call
handler.close() in runWorker before closing the inbox on shutdown
- Override
close() in _AndroidReplayHandler to release _bitmap and _nativeReplay
- Release the
Bitmap$Config.ARGB_8888 reference after passing it to createBitmap$10
Summary
_AndroidReplayHandler(the isolate-side replay screenshot handler) leaks JNI object references in three places.Details
1.
Bitmap$Config.ARGB_8888leaks on every bitmap creationhttps://github.com/getsentry/sentry-dart/blob/a7f011a3/packages/flutter/lib/src/native/java/android_replay_recorder.dart#L134
Bitmap$Config.ARGB_8888is a static getter that returns a new JNI reference each call (the generated binding comments say "must be released after use"). This reference is passed tocreateBitmap$10and then abandoned — it leaks every time a new bitmap is created (first capture, and on every dimension change).2.
_bitmapnever released on isolate shutdownhttps://github.com/getsentry/sentry-dart/blob/a7f011a3/packages/flutter/lib/src/native/java/android_replay_recorder.dart#L98
The cached
Bitmapis released when dimensions change (line 126), but when the worker isolate shuts down the bitmap is abandoned without releasing.3.
_nativeReplaynever released on isolate shutdownhttps://github.com/getsentry/sentry-dart/blob/a7f011a3/packages/flutter/lib/src/native/java/android_replay_recorder.dart#L99-L103
The
ReplayIntegrationJObject obtained in the constructor is stored as a field but never released.Root cause
WorkerHandlerhas noclose()lifecycle callback. When the isolate receives the shutdown command, it closes theReceivePortwithout giving the handler a chance to release resources.Suggested fix
FutureOr<void> close()method toWorkerHandler(default no-op)handler.close()inrunWorkerbefore closing the inbox on shutdownclose()in_AndroidReplayHandlerto release_bitmapand_nativeReplayBitmap$Config.ARGB_8888reference after passing it tocreateBitmap$10