An out-of-memory (OOM) crash happens when the operating system terminates your app because it's using too much memory. OOMs are hard to catch because many crash reporters never see them: the app is simply killed. Here's what causes OOM crashes on iOS and Android and how to avoid them.
As might be evident from their name, OOMs occur when the OS decides to terminate your app to free up the memory it uses. OOMs are further divided into background OOMs (BOOMs) and foreground OOMs (FOOMs) depending on the app's state when they occur.
BOOMs are more often caused by the app in the foreground consuming excess memory than by excessive memory use by an app or apps in the background. You generally have no control over BOOMs, but they also have a minimal impact on your app's UX since your app does not unexpectedly terminate while in the foreground where users can see it.
FOOMs are usually what people are referring to when they talk about OOMs and these are the ones that are caused by your app using too much memory. They are extremely disruptive to the user experience, but the good news is you can largely avoid them with some efficient memory management.
Why don't OOMs show up in most crash reports?
Standard crash reporting tools rely on uncaught exception handlers. When the Java or Swift runtime encounters an unhandled exception, the handler fires before the process terminates and reports the crash.
OOM terminations bypass this entirely. When the OS decides to kill an app for memory pressure, it sends a SIGKILL signal. SIGKILL cannot be caught or handled by the app. There is no exception, no stack trace and no opportunity for the crash handler to run. The process simply stops.
The result: OOM crashes are invisible to any tool that relies on exception handlers alone.
How detection works without an exception handler
The approach is to infer the OOM on the next launch rather than catching it at the moment it happens. On startup, the app checks whether the previous session ended normally. If the previous session ended without a crash report, without the user explicitly closing the app and without a background transition, an OOM termination is the likely explanation.
This inference approach works but has limits:
- It can't produce a stack trace, because no stack trace was captured at the time of termination.
- It can't tell you exactly which allocation pushed the app over the limit, only that memory pressure was the cause.
- It requires the session before the OOM to have been recorded, so the context (screens visited, actions taken, memory growth pattern) can be reviewed.
What makes OOM data actionable despite these limits is the session leading up to the termination. If OOM terminations are consistently preceded by a specific screen, a specific action sequence or a specific session length on a specific device tier, that pattern points to where the leak or allocation spike is happening.
What causes OOM errors on Android?
Android OOM errors happen when an app requests more memory than the system can provide, either because the device is already under pressure from other processes or because the app itself has accumulated more than its share.The most common causes:
- Memory leaks. An object is allocated, used and then not released because something still holds a reference to it. The garbage collector can't free it. Over a long session, leaked objects accumulate until the system kills the process. Common sources are Context references held by singletons, listeners that aren't unregistered in onDestroy, and static fields holding Views or Activities.
- Large bitmaps loaded without sampling. Loading a full-resolution image from disk or a URL into a Bitmap without downsampling or compression allocates memory proportional to the image dimensions, not the display size. A 4000x3000px photo decoded at full resolution uses roughly 45MB of memory. On a device with 3GB RAM under load, a screen with several such images will trigger OOM.
- Background work that stays alive too long. Services, BroadcastReceivers and background threads that accumulate state over time without bounds can grow memory usage past what the foreground app needs, especially on devices where Android's background process limits allow several services to coexist.
- Third-party SDK allocations. Analytics SDKs, ad networks and media players sometimes allocate large buffers or caches that aren't bounded or cleared on app resume. An app that integrates several SDKs compounds their individual memory costs.
How to profile Android memory
- Use Android Studio's Memory Profiler to watch heap allocation over a session. A heap that grows continuously without returning to baseline during idle periods is leaking.
- LeakCanary is the standard library for detecting reference leaks in development. It intercepts garbage collection and reports any object that should have been collected but wasn't, with a chain showing what's holding the reference.
- In production, watch OOM termination rate segmented by device RAM tier. Devices with 3GB or less surface leaks significantly faster than flagships. If OOM rate is elevated on low-RAM devices but not on high-RAM ones, the issue is accumulation rather than a spike.
Out-of-memory errors are a silent killer of your crash-free session benchmarks, making it nearly impossible to hit a 99.9% target. As mentioned earlier, avoiding OOM "crashes" in your app really boils down to making sure that your app is using, retaining, and freeing memory in an efficient manner. Here are some tips and best practices you can use to reduce your app's memory footprint and eliminate OOMs.
Know your limits
Before you start worrying about how much memory your app is going to use, you must first understand how much memory you have available to work with. This of course means that you have to think carefully about which devices you want your app to support. Next, you need to find out the memory threshold at which the OS decides to terminate your app. This tool from developer Jan Ilavsky can help you do just that, and you can check this StackOverflow post for the results of all iOS devices till the iPhone 11 Pro Max.
Plug your leaks
Memory leaks are one of the main culprits that can cause an OOM, especially retain cycles. Retain cycles occur when two or more objects hold a strong reference to each other causing them to remain held in memory indefinitely. You can check out this great post from DoorDash about how they found and fixed retain cycles in their iOS app.
Don't cache out
The cache can be a great friend when you use it for frequently accessed objects that use a lot of memory, but if you abuse it and start caching too many objects you can quickly force the OS to terminate your app. Images are a prime example of objects that can eat up your cache quickly. You should always purge your cache of objects that use a lot of memory once they're not needed and preferably apply a limit to your cache size.
Track your OOM rate
Reducing your app's memory footprint is great but it is of little use if you can't actually see the effect it is having. Detecting and tracking OOM crashes that occur in your app and profiling your app's memory usage is the best way to see if your memory optimization is working and has the desired effect. Using a tool like Luciq that can detect and report OOMs will help you keep track of them and see the result of your efforts.
To see how AI tools compare when automatically fixing crashes like OOMs, read our benchmarking of AI coding assistants for mobile app crash resolution.
For more tips on reducing your memory footprint and optimizing its usage, you can check out this post.
Catch the OOMs other tools miss
OOMs are hard to catch because the OS ends the app without a normal crash report. Luciq's SDK tracks memory state inside the app, so it catches OOM terminations basic crash reporting misses and shows the session leading up to each one.



