Skip to content

Fix OOM crashes during screenshot comparison#281

Draft
djette-st wants to merge 2 commits intomainfrom
fix-oom
Draft

Fix OOM crashes during screenshot comparison#281
djette-st wants to merge 2 commits intomainfrom
fix-oom

Conversation

@djette-st
Copy link
Collaborator

Summary

  • Recycle captured bitmap in createBitmapFromActivity() after saving to disk, eliminating ~9.6 MB leaked per test invocation
  • Switch buffer allocation to native memory using ByteBuffer.allocateDirect() instead of IntBuffer.allocate(), moving ~19.2 MB of buffer allocation off the JVM heap entirely
  • Add try/finally guards in ParallelPixelProcessor.analyze() and transform() to guarantee buffer cleanup on exceptions
  • Recycle diff bitmap in HighContrastDiff.generate() after saving to disk
  • Add overflow guard in allocateSafely() for large capacity * INTEGER_BYTES computations, widening LowMemoryException.requestedAllocation to Long

Context

The library intermittently crashes with LowMemoryException / OutOfMemoryError when the instrumentation process receives a small JVM heap (as low as 16 MB) despite the emulator having 2 GB of RAM. The root cause is a combination of bitmap leaks and heap-based buffer allocation that exhausts the constrained JVM heap.

Peak JVM heap during comparison was ~48 MB (captured bitmap leak + reloaded bitmap + baseline bitmap + two IntBuffers). With these fixes, IntBuffers move to native memory and the leaked bitmap is recycled, reducing peak heap to ~19.2 MB (just the two bitmaps, whose pixel storage is native on API 26+).

Test plan

  • All Library unit tests pass
  • All Library androidTests pass (56 tests)
  • LegacySample screenshot tests pass (88 tests)
  • FlixSample screenshot tests pass (20 tests)
  • FlixLibrary screenshot tests pass (3 tests)
  • Plugin unit tests pass
  • KtLint checks pass for all modules
  • Build validation passes for Accessibility, ComposeExtensions, FullscreenCaptureMethod, Plugin
  • Verify on emulator with constrained heap (16 MB) that OOM no longer occurs

- Recycle captured bitmap in createBitmapFromActivity() after saving to
  disk, eliminating ~9.6 MB leaked per test invocation
- Switch IntBuffer allocation from heap (IntBuffer.allocate) to native
  memory (ByteBuffer.allocateDirect) to bypass JVM heap constraints
- Add overflow guard for large capacity * INTEGER_BYTES computations
- Wrap ParallelPixelProcessor analyze() and transform() in try/finally
  to guarantee buffer cleanup on exceptions
- Recycle diff bitmap in HighContrastDiff.generate() after saving
- Update ImageBufferTest to reflect direct buffer allocation behavior
Replace full-image IntBuffer allocation with stripe-based processing
to dramatically reduce peak Java heap usage during bitmap comparison.

- Process bitmaps in horizontal stripes using Bitmap.createBitmap()
  sub-regions and copyPixelsToBuffer(), keeping per-stripe heap usage
  under ~1 MB instead of ~19 MB for full-image buffers
- Stripe height is dynamically calculated based on available heap memory
- Revert ByteBuffer.allocateDirect() change (no benefit on Android where
  direct buffers use VMRuntime.newNonMovableArray on the Java heap)
- Add mockBitmapCreateBitmap() test helper and update all processor tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant