第一章:Bitmap初印象——什么是Bitmap、像素与色深、Bitmap在内存中的样子
各位同学,咱们今天正式开讲《Bitmap内存管理全流程精讲》。
第一节课,我想先聊聊Bitmap最基础的东西。说白了,就是回答三个问题:Bitmap到底是什么?像素和色深是怎么回事?它在内存里长什么样?
嗯,别小看这些基础概念。我见过太多开发者在内存优化上栽跟头,追根溯源,都是对Bitmap的“底子”没吃透。我自己刚入行那会儿,也踩过类似的坑。
1.1 什么是Bitmap?
Bitmap,中文叫“位图”。你可以把它想象成一张网格纸。
这张网格纸由很多小格子组成,每个格子就是一个像素。每个像素里存着一个颜色值。整张网格纸拼在一起,就形成了一幅完整的图像。
举个例子:一张 100x100 的Bitmap,就是横向100个格子,纵向100个格子,总共10000个像素。每个像素里存着颜色信息。
核心定义:Bitmap = 像素矩阵 + 每个像素的颜色数据
我在项目中遇到过一件事:有个同事加载了一张 4000x3000 的照片,直接OOM了。他当时很困惑:“不就一张图吗?” 我告诉他:“你算算,4000x3000 = 1200万像素。如果每个像素占4字节,那就是48MB。再加上解码过程中的临时内存,不崩才怪。”
所以,理解Bitmap,首先要理解它的“像素”和“色深”。
1.2 像素与色深
像素是图像的最小单元。每个像素记录一个颜色值。
色深(Color Depth),也叫位深,指的是每个像素用多少位(bit)来表示颜色。色深越大,能表示的颜色越丰富,但占用的内存也越大。
常见的色深格式有这些:
| 格式 | 每像素位数 | 每像素字节数 | 颜色范围 | 典型场景 |
|---|---|---|---|---|
| ARGB_8888 | 32位 | 4字节 | 1670万色 + Alpha通道 | Android默认格式,高质量显示 |
| RGB_565 | 16位 | 2字节 | 65536色,无Alpha | 节省内存,适合无透明度的图片 |
| ARGB_4444 | 16位 | 2字节 | 4096色 + Alpha | 已废弃,质量差 |
| Alpha_8 | 8位 | 1字节 | 仅透明度 | 蒙版、遮罩 |
我个人习惯,在不需要透明度的场景下,尽量用 RGB_565。你想想看,一张图用 ARGB_8888 要4字节每像素,换成 RGB_565 只要2字节,内存直接砍半。我在做相册应用时,缩略图全部用 RGB_565,效果几乎看不出差别,但内存占用降了一大截。
小技巧:如果你的图片不需要透明度,并且对色彩精度要求不高,优先考虑 RGB_565。这是最直接的内存优化手段之一。
1.3 Bitmap在内存中的样子
好,现在咱们聊聊Bitmap在内存里到底是怎么存的。
说白了,Bitmap在内存中就是一块连续的字节数组。每个像素按照色深格式,依次排列在这块内存里。
举个例子:一张 2x2 像素的Bitmap,使用 ARGB_8888 格式。
它在内存中的布局是这样的:
内存地址: [0x00] [0x01] [0x02] [0x03] | [0x04] [0x05] [0x06] [0x07] | ...
|-------- 像素(0,0) --------| |-------- 像素(0,1) --------|
A R G B A R G B
0xFF 0xCC 0x66 0x33 0xFF 0xAA 0x55 0x22
每个像素占4字节,顺序是:Alpha(透明度)、Red(红)、Green(绿)、Blue(蓝)。
整张图的数据就是:像素(0,0) + 像素(0,1) + 像素(1,0) + 像素(1,1),依次排列。
所以,Bitmap占用的内存大小计算公式很简单:
内存大小 = 宽度 × 高度 × 每像素字节数
例如:1920x1080 的 ARGB_8888 图片,内存 = 1920 × 1080 × 4 = 8,294,400 字节 ≈ 7.9MB
我曾经犯过一个低级错误:在加载一张 4096x4096 的图片时,忘了考虑内存对齐。实际上,Android系统在分配Bitmap内存时,每行的字节数可能会做对齐处理(通常是 4字节对齐)。也就是说,实际占用的内存可能比理论值稍微大一点点。虽然差别不大,但在极端情况下,这个“一点点”可能就是压死骆驼的最后一根稻草。
注意:在Android 3.0之前,Bitmap的像素数据存储在Dalvik堆中。3.0之后,像素数据移到了Native堆。这意味着,Bitmap的内存回收不再完全依赖Java GC,而是需要主动调用 recycle() 或者依赖 Native 层的释放。这一点在后续章节会详细讲。
1.4 为什么理解这些很重要?
你可能会问:“知道这些有什么用?”
用处大了去了。
- 内存优化:知道每个像素占多少字节,你就能精确计算出加载一张图需要多少内存。是选 ARGB_8888 还是 RGB_565,心里有数。
- OOM预防:我见过太多人加载大图直接崩。如果你能提前算一下内存占用,很多OOM是可以避免的。
- 性能调优:Bitmap的拷贝、缩放、旋转,本质上都是在操作这块连续内存。理解它的布局,你才能写出高效的代码。
嗯,这节课就到这里。下一节,我们会深入Bitmap的创建与加载流程,看看一张图片从文件到内存,到底经历了什么。
记住:基础不牢,地动山摇。Bitmap的内存管理,从理解像素和色深开始。
公众号:蓝海资料掘金营,微信deep3321