RevenueCat / RevenueCat/react-native-purchases
OutOfMemoryError when displaying paywall with social proof carousel
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1.2k
- Forks
- 117
- Avg merge
- 14h 40m
- Merged PRs (30d)
- 40
Description
- I have updated Purchases SDK to the latest version
- I have read the Contribution Guidelines
- I have searched the Community
- I have read docs.revenuecat.com
- I have searched for existing Github issues
Describe the bug
The RevenueCat native Compose paywall UI (react-native-purchases-ui) causes consistent OutOfMemoryError crashes on Android when displaying paywall with social proof carousel. The paywall exhausts the 256MB heap limit during its initial render, even with a simplified template containing no custom images or complex UI elements.
1. Environment
- Platform: Android
- SDK version:
react-native-purchases: 9.6.6react-native-purchases-ui: 9.6.6
- OS version: Android 16
- Android Studio version: N/A (using Expo managed workflow)
- React Native version: 0.79.6
- SDK installation: npm/yarn with Expo managed workflow
- How widespread is the issue: 100% reproducible on test devices when displaying hard paywall via
RevenueCatUI.Paywall
2. Debug logs
The crash occurs during the initial Compose UI measurement/layout phase:
2025-11-18 14:17:38.341 21374-21374 com.example.app com.example.app W Throwing OutOfMemoryError "Failed to allocate a 4224 byte allocation with 2036688 free bytes and 1988KB until OOM, target footprint 268435456, growth limit 268435456; giving up on allocation because <1% of heap free after GC."
2025-11-18 14:17:38.347 21374-21374 AndroidRuntime com.example.app E FATAL EXCEPTION: main
Process: com.example.app, PID: 21374
java.lang.OutOfMemoryError: Failed to allocate a 4224 byte allocation with 2036688 free bytes and 1988KB until OOM, target footprint 268435456, growth limit 268435456; giving up on allocation because <1% of heap free after GC.
at android.os.Parcel.nativeReadString8(Native Method)
at android.os.Parcel.readString8NoHelper(Parcel.java:3436)
at android.os.Parcel$ReadWriteHelper.readString8(Parcel.java:545)
at android.os.Parcel.readString8(Parcel.java:3415)
at android.view.DisplayShape$1.createFromParcel(DisplayShape.java:261)
at android.view.InsetsState.readFromParcel(InsetsState.java:852)
at android.window.WindowMetricsController.getWindowInsetsFromServerForDisplay(WindowMetricsController.java:117)
at androidx.compose.material3.adaptive.AndroidWindowAdaptiveInfo_androidKt.currentWindowSize(AndroidWindowAdaptiveInfo.android.kt:58)
at androidx.compose.material3.adaptive.AndroidWindowAdaptiveInfo_androidKt.currentWindowAdaptiveInfo(AndroidWindowAdaptiveInfo.android.kt:37)
at com.revenuecat.purchases.ui.revenuecatui.components.iconcomponent.IconComponentStateKt.rememberUpdatedIconComponentState(IconComponentState.kt:50)
at com.revenuecat.purchases.ui.revenuecatui.components.iconcomponent.IconComponentViewKt.IconComponentView(IconComponentView.kt:47)
at com.revenuecat.purchases.ui.revenuecatui.components.ComponentViewKt.ComponentView(ComponentView.kt:81)
at com.revenuecat.purchases.ui.revenuecatui.components.stack.StackComponentViewKt$MainStackComponent$stack$1$2$1$1.invoke(StackComponentView.kt:513)
[... extensive Compose layout stack trace ...]
at com.revenuecat.purchases.react.ui.views.ComposeViewWrapper.onMeasure(ComposeViewWrapper.kt:52)
Key observations from logs:
- Memory pressure builds up during onboarding:
Clamp target GC heap from 351MB to 256MB - Multiple blocking GC events before crash:
WaitForGcToComplete blocked Alloc(400-600ms delays) - Heap is at 254-255MB before paywall renders
- Crash occurs during Compose UI measurement, specifically when calculating adaptive window metrics
3. Steps to reproduce
Setup:
- Create a React Native app with Expo managed workflow
- Add RevenueCat paywall using
react-native-purchases-uiat the end of onboarding - Use the default offering
Expected behavior:
Paywall should render successfully without memory issues.
Actual behavior:
App crashes with OutOfMemoryError during paywall's initial Compose measurement phase. The crash is 100% reproducible.
Additional observations:
- Removing all WebP images from onboarding slides does NOT fix the issue
- Removing all custom images from the paywall template does NOT fix the issue
- Memory is already at 254-255MB before the paywall attempts to render
- Adding
android:largeHeap="true"does NOT fix the issue (still crashes at 256MB limit)
4. Other information
Root cause analysis:
The RevenueCat Compose paywall UI appears to have excessive memory overhead when rendering paywalls with social proof carousel. The stack trace shows it's crashing during:
- Adaptive window metrics calculation (
currentWindowAdaptiveInfo) - Icon component state management
- Complex nested Stack/Carousel component composition
The issue appears to be related to:
- Jetpack Compose memory overhead - The native Compose UI requires significantly more memory than React Native views
- Complex component hierarchy - Multiple nested stacks, carousels, and adaptive layouts
- No memory cleanup between screens - Previous onboarding state remains in memory
Workarounds attempted:
- ✅ Removed all images from onboarding slides
- ✅ Simplified paywall template (removed all custom images)
- ✅ Added
android:largeHeap="true" - ❌ None of these resolved the issue
Removing the carousel:
- ✅ This seems to have fixed the crash
Device specifications:
- Heap limit: 256MB (standard Android allocation)
- Memory available at crash: ~2MB (254MB/256MB used)
- React Native memory footprint before paywall: ~200MB
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the crash by displaying RevenueCatUI.Paywall with the social proof carousel in the described Expo setup. Start with ComposeViewWrapper.kt, IconComponentState.kt, and the stack/carousel components named in the trace, comparing behavior with the carousel removed. Done means the paywall renders without an OutOfMemoryError under the reported conditions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, react-native
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100