BitmapFactory Memory Management for AVIF Assets
Android’s BitmapFactory manages memory when loading
high-resolution AVIF (AV1 Image File Format) assets by streaming
compressed data through native decoders and allocating pixel buffers
directly in native memory. Because AVIF provides high compression
ratios, a small file can expand into an enormous uncompressed bitmap in
memory. BitmapFactory controls this footprint through
native heap allocation, configuration parameters like
inSampleSize and inPreferredConfig, reusable
memory buffers via inBitmap, and zero-copy GPU transfers
with Bitmap.Config.HARDWARE.
Native Heap Allocation
Since Android 8.0 (API level 26), pixel data decoded by
BitmapFactory is stored in the native C++ heap rather than
the Java Virtual Machine (JVM) heap. When an AVIF asset is
loaded—supported natively since Android 12 (API level 31)—the underlying
framework uses platform decoders (such as libgav1 or
hardware-accelerated decoders via the media framework). The compressed
AVIF byte stream is parsed natively, and raw RGBA pixel data is written
straight to native memory allocations. While this prevents Java
OutOfMemoryError (OOM) crashes caused by JVM heap
saturation, unconstrained native allocations can still exhaust total
system RAM and trigger the Android Low Memory Killer (LMK).
Pre-Allocation
Inspection via inJustDecodeBounds
High-resolution AVIF files often have relatively small file sizes due to AV1 intra-frame compression, masking the massive memory requirement of their decoded raw dimensions. To manage memory before allocation occurs:
- Set
BitmapFactory.Options.inJustDecodeBounds = true. - Decode the file source. The native decoder reads only the AVIF container and image sequence headers to query image metadata.
- The method returns
nullfor theBitmap, but populatesoutWidth,outHeight, andoutMimeType.
This step requires negligible memory and allows the application to calculate the exact target memory footprint before initiating pixel decompression.
Memory Reduction
via Downsampling (inSampleSize)
Once the original dimensions are known, the memory footprint can be
scaled down at decode time using inSampleSize. Setting
inSampleSize to an integer power of two (e.g., 2, 4, 8)
instructs the native decoder to subsample the AV1 pixels during the
decoding pipeline.
For instance, an 8K AVIF image decoded at full resolution in standard 8-bit RGBA requires approximately 134 MB of raw native memory: \[\text{Width (7680)} \times \text{Height (4320)} \times 4 \text{ bytes per pixel} \approx 132.7 \text{ MB}\]
Setting inSampleSize = 2 reduces both dimensions by
half, shrinking the native memory footprint by a factor of four to
roughly 33 MB before the pixel buffer is committed.
Color Depth and Pixel Format Selection
AVIF natively supports High Dynamic Range (HDR) with 10-bit and
12-bit color depths. BitmapFactory manages memory
consumption through inPreferredConfig:
Bitmap.Config.ARGB_8888: Standard 8-bit per channel allocation (4 bytes per pixel). This is the standard fallback for SDR targets.Bitmap.Config.RGBA_F16: Used for wide-gamut and HDR AVIF content. It allocates 16-bit half-precision floats per channel (8 bytes per pixel), doubling the native memory requirement compared toARGB_8888.Bitmap.Config.HARDWARE: Creates an immutableGraphicBufferbacked by Android'sAHardwareBuffer. This bypasses system RAM duplication by mapping the image directly to GPU-accessible memory. When an AVIF is decoded solely for UI display,HARDWAREconfiguration optimizes performance and reduces CPU-side memory overhead.
Buffer Reuse via
inBitmap
To eliminate memory fragmentation and native garbage collection
thrashing during continuous high-resolution image decoding (such as in
lists or pagers), BitmapFactory.Options.inBitmap allows an
existing, mutable Bitmap allocation to be reused.
When decoding an AVIF into an existing inBitmap, the
underlying native decoder writes new pixel data directly into the
allocated memory buffer without requesting a new allocation from the
operating system, provided the target buffer's byte count is greater
than or equal to the incoming decoded AVIF's byte allocation
requirements.