fix(replay): stop reserving an uncompressed frame per screenshot - #755
Draft
posthog[bot] wants to merge 1 commit into
Draft
fix(replay): stop reserving an uncompressed frame per screenshot#755posthog[bot] wants to merge 1 commit into
posthog[bot] wants to merge 1 commit into
Conversation
The Base64 encoder buffer in Bitmap.base64 was sized from the bitmap's allocationByteCount, so every capture reserved a second full uncompressed frame - about 10 MB on a 1080x2400 screen - for a payload that lands in the tens of kilobytes. At the default 1 second capture cadence that repeated allocation is what ran small heaps out of memory. The buffer is now sized from a compressed estimate, and the compressed bytes stream straight into the encoder instead of being held in an intermediate array. Generated-By: PostHog Desktop Task-Id: 26fba2a7-1ba9-42fe-927c-f9daa9f1d107
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

💡 Motivation and Context
Problem
Bitmap.base64sized its output stream from the bitmap'sallocationByteCount— the uncompressed frame. On a 1080x2400 screen that reserved a ~9.9 MBbyte[]on the Java heap for a WEBP payload that lands in the tens of kilobytes. On a 512 MB heap, a contiguous 10 MB request every second is the allocation that fails.PostHogReplayIntegrationforces screenshot mode whenever the SDK is not native, so every React Native Android app on session replay runs this path with no way to opt out.Peak Java heap per capture — 1080x2400 frame, lossy WEBP quality 30, ~40 KB payload:
4 × w × h)w × h / 12)byte[]copyStringChanges
Base64OutputStream, so the compressed payload is never held in a separate array.The wire format is unchanged apart from a trailing newline that the streaming encoder does not always emit. That newline sits outside the Base64 payload and every decoder ignores it.
Note
This is the cheap half of the fix. Two larger follow-ups stay open: an optional capture downscale, and reusing the capture bitmap while the view size holds. Both change replay output or lifetime and need a device to validate. Neither is needed for this allocation, because bitmap pixels live in native memory on API 26+ while the buffer this PR shrinks is on the Java heap that throws
OutOfMemoryError.💚 How did you test it?
BitmapBase64Test(Robolectric, 5 cases): the data URI matches whatBase64.encodeToStringproduced before, for a single-line and a wrapped payload; the payload decodes back to the exact compressed bytes; the WEBP media type is right; a recycled bitmap still returns null.:posthog-android:testDebugUnitTestsuite andspotlessCheckpass.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Fully autonomous
OutOfMemoryError; the oversizedbyte[]does. Fixing the buffer targets the reported failure, and the other two are performance work that needs device validation.Base64.NO_WRAP, which would shrink the payload ~1.4% and produce a spec-valid data URI. It changes what is sent, which this PR should not do.w × h / 3was still 8-60x larger than real payloads./12keeps enough headroom that the array never grows in practice, and an under-estimate only costs one array copy.Created with PostHog Desktop from this inbox report.