OutOfMemoryError when displaying paywall with social proof carousel
- [x] I have updated Purchases SDK to the latest version
- [x] I have read the Contribution Guidelines
- [x] I have searched the Community
- [x] I have read docs.revenuecat.com
- [x] 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.6 -
react-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
👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!
Hi @rgomezp, thanks for reporting. An OOM error is tricky, in that the culprit is often not what's causing the crash. It's simply the straw that broke the camel's back. To fix this it's important to figure out what's in the heap before the Paywall is shown, to identify possible memory leaks.
You can do that using Android Studio's Profiler (docs). You can also try adding LeakCanary to your app, although that is a native Android library.
Do you have a reproducer project?