Android系统内存是非常有限的,一定要好好珍惜,不要等到OOM才追悔莫及。Android app中最占用内存的也是就图片了。那么我们就有必要弄清楚,Bitmap图片在Android中占用了多少内存。
图片在内存中的存储模型
我们可以将图片在内存中的存储模型想象成一个长方体,它的长、宽、高分别表示图片的宽度、高度、颜色深度。那么Bitmap图片在内存中的大小计算就变成了计算长方体的体积:Bitmap Memroy size = width * height * 颜色深度
,那么这里的颜色深度是什么意思呢?
色彩存储
我们知道ARGB指的是一种色彩模式,里面A代表Alpha,R表示Red,G表示Green,B表示Blue,所有的可见色都是由红绿蓝组成的,所以红绿蓝又称为三原色,每个原色都存储着所表示颜色的信息值,下表中对四种颜色模式的详细描述,以及每种色彩模式占用的字节数(也就是颜色深度值)
颜色深度简单说就是最多支持多少种颜色。一般是用“位”来描述的。
模式 | 描述 | 占用字节 |
---|---|---|
Bitmap.Config.AlPHA | Alpha由8位组成 | 1B |
Bitmap.Config.ARGB_4444 | 4个4位组成16位,每个色彩元素站4位 | 2B |
Bitmap.Config.ARGB_8888 | 4个8为组成32位,每个色彩元素站8位 | 4B |
Bitmap.Config.RGB_565 | R为5位,G为6位,B为5位共16位,没有Alpha | 2B |
实例讲解
例如下面这张图片,在磁盘中的大小166KB,1000 x 563像素,那么这个Bitmap图片在内存中占用多少空间呢?
这是只有你才懂的图~
用上面的图片做为实验材料进行测试。由于我的手机是1080P,所以将图片放入drawable-xxhdpi
,然后看代码:
至于为什么,我要将图片放入drawable-xxhdpi而不是drawable-xhdpi,或者其他目录,与我本身设备的像素密度有关。不在本文的分析范围,以后再做分析。如果你用下面的代码测试,一定要将图片放入到与测试机像素密度对应的目录下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
private void bitmapMemorySize() { BitmapDrawable drawable = (BitmapDrawable) getResources().getDrawable( R.drawable.icho); Bitmap bitmap = drawable.getBitmap(); Log.d(MainActivity.class.getSimpleName(), "bitmap memory size:" + sizeOfBitmap(bitmap)); int height = bitmap.getHeight(); int width = bitmap.getWidth(); int rowBytes = bitmap.getRowBytes();// 每一行在内存中所占的字节 int colorDeep = rowBytes / width;// 颜色深度 Log.d(MainActivity.class.getSimpleName(), "bitmap height:" + height); Log.d(MainActivity.class.getSimpleName(), "bitmap width:" + width); Log.d(MainActivity.class.getSimpleName(), "bitmap rowBytes:" + rowBytes); Log.d(MainActivity.class.getSimpleName(), "bitmap colorDeeps:" + colorDeep); } |
1 2 3 4 5 6 |
01-07 15:39:29.769: D/MainActivity(8827): bitmap memory size:2252000 01-07 15:39:29.769: D/MainActivity(8827): bitmap height:563 01-07 15:39:29.769: D/MainActivity(8827): bitmap width:1000 01-07 15:39:29.769: D/MainActivity(8827): bitmap rowBytes:4000 01-07 15:39:29.769: D/MainActivity(8827): bitmap colorDeeps:4 |
看上面的日志可以发现Bitmap的宽高分别为1000X563与文章开头提到的一致,颜色深度=4,Bitmap size=2252000/1024=2199KB,是其在磁盘中的大小166KB的13倍之多。
为什么图片在内存中比磁盘中大
因为图片在磁盘中是经过压缩的(通过JPG,PNG这些格式存储)。图像文件占的磁盘空间大小还和磁盘的文件格式有关。如:NTFS最小单位为4KB 所以图像文件大小肯定是4KB的倍数。当图片加载到内存之后,就会解压缩,大小就由像素点的个数和单位像素所占字节相关。
图片选择合理的解码方式
出于节省Android内存的考虑,应该如何选择色彩模式呢?第一点:应用内置的的PNG图片,如果不出现粗糙的光栅组,出于节省内存的角度可以考虑使用ARGB_4444,其它仍保留使用ARGB_8888方式;对于没有Alpha通道的jpg图片,使用ARGB_8888是明显浪费的,建议使用RGB_565。
总结
Android处理大图的时候,为了防止内存泄漏,我们需要对图片进行压缩处理,按照合适的比率调整图片的simpleSize。例如:1080P的图片,在720P的屏幕上面显示。如果按照原清晰度显示,视觉上也看不出任何效果。还可以调整图片色彩模式来节省内存空间。留下一个问题,Android如何加载类似微博长图或者超大图呢?耐心的等待下一篇文章吧。