前言
加载一张Bitmap图片,占用内存是多大呢?
1简介
我们在开发程序过程中,经常会碰到OOM问题,分析问题,发现主要和图片相关,只知道需要去缩减图片大小。但还完全不懂得一张图片具体占用了多少内存空间?我第一次碰到这样的问题也很疑惑,那就让我们一起来解开这个谜题。(以下图片以Bitmap代替)
2计算公式
目前大家比较公认的计算公式如下
bitmap占用内存 = bitmap的宽度 x bitmap的长度 x 单位像素占用的字节数。
从上面可以看得出,最直接的影响那就是bitmap的宽度和长度,而不是bitmap的占用存储空间大小。当然还有一个很重要的因子——“单位像素占用的字节数”,这个因子是变化的。
3可变因子
从上述公式里面提到的“单位像素占用的字节数”,其实是不一样的,这个不一样,则取决于将Bitmap读取到内存时设置的参数。
我们一般通过BitmapFactory.decodeXXX 方法里面可以传入BitmapFactory.Options参数。而该参数底下有一个inPreferredConfig参数,Bitmap.Config类型,它是枚举类型,值可以是
ALPHA_8
只有透明度,没有任何RGB值,一个像素占用1个字节(byte)。
ARGB_4444
每一个像素点由4个,A(Alpha)、R(Red)、G(Green)、B(Blue)值表示。每一个占用4位(bit),所以总共占用16bit=16/8(byte)=2byte。也即每一个像素占用2字节。
这种格式的图片,显示效果会比较差,不推荐使用。
ARGB_8888
android手机上默认的格式,同时也是电脑上通用的格式。也是由4个值表示的,但每一个值占用8bit,所以总共是32bit=4byte。也即每一个像素占用4个字节。
RGB_565
没有透明度(alpha),所以,没法支持半透明或是全透明。只有R(占用5bit),G(占用6bit),B(占用5bit),总共16bit=2byte。也即,每一个像素占用2字节。
4占用内存实例
有了上述的公式,那么我们可以来算一笔账。如果一个有一张100x100的图片,使用不同可变因子的情况下,它实际占用内存是多大的呢?
1)ALPHA_8
100 x 100 x 1byte = 10000byte ≈ 10k
2)ARGB_4444
100 x 100 x 2byte = 20000byte ≈ 20k
3)ARGB_8888
100 x 100 x 4byte = 40000byte≈ 40k (标准)
4)RGB_565
100 x 100 x 2byte = 20000byte≈ 20k
由于图片占用内存指的就是在Native中占用的内存,因为我们可以简单在认为这个就是bitmap实际占用的内存。
5内存回收
Android在4.0之前,Bitmap的内存是分配在Native(C/C++)堆中的,可以调用recycle()方法来回收内存。
但在Android 4.0开始,Bitmap的内存是分配在Dalvik堆中(Java),即使调用recycle(),也不会立马回收内存,但建议继续使用这个方法来回收。
使用recycle的技巧如下:
// 先判断是否已经回收
if(bitmap !=null
&& !bitmap.isRecycled()){
// 回收并且置为null
bitmap.recycle();
bitmap = null;
}
因为,建议在Bitmap不用的情况下,主动回收资源,同时如果定义Bitmap或Drawable的变量,建议采用WeakReference引用。一旦系统发现内存不足,会主动回收资源,使用弱引用,可以让系统尽可能释放更多的内存,从而避免OOM。