OOM Bitmap Resource Analysis and Optimization
Article Summary
Ansgar Lin from Grindr Engineering found a single placeholder image consuming 8.3MB of memory at runtime. On devices with only 16-32MB Java heap, that's a recipe for constant crashes.
Most Android OOM crashes trace back to oversized Bitmaps lurking in memory. Lin walks through using Android Studio Profiler to hunt down memory hogs, explaining how Android 8+ changed where pixel data lives (native heap vs Java heap), and evaluating real solutions beyond the usual advice.
Key Takeaways
- A 1440x1440 placeholder image consumed 8.3MB, nearly half of low-end device memory
- WebP and cruncher only shrink APK size, images still balloon into huge Bitmaps
- VectorDrawable reduced runtime memory from 8.3MB to 600KB for the same asset
- Pre-Android 21 devices cache VectorDrawableCompat by size, causing redraws
- Manual heap dumps required for profiling on devices below Android 21
Switching from raster images to VectorDrawable cut runtime memory usage by 93%, but comes with performance tradeoffs that require case-by-case evaluation.
About This Article
Grindr Engineering ran into a problem where Android 8+ stores Bitmap pixel data in the native heap instead of the Java heap. This made memory profiling work differently depending on the OS version, which made it harder to figure out what was actually causing OOM crashes.
Ansgar Lin used Android Studio's Memory Profiler to see where the data was being stored. He then looked at VectorDrawable as a way to replace the raster image assets. The fix only needed config changes like setting vectorDrawables.useSupportLibrary = true and using app:srcCompat in the XML.
VectorDrawableCompat used just 2KB on devices before Android 21, compared to 8.3MB for the original placeholder. The images still looked good and they didn't need to do runtime scaling or caching anymore.