Bitmap的内存

在我们的日常开发中,不免经常与Bitmap打交道。在为我们渲染美丽的界面的同时,也经常会带给我们许多的苦恼。比如你会发现,Bitmap占用的内存通常很大,很多OOM的原因都是由于Bitmap占用的内存过大导致的。那么到底为什么Bitmap会占用很大的内存,而我们又该怎么做来避免呢?下面我们来简单的了解下Bitmap。

如何计算Bitmap的内存

1.png

我们先来看上面这张图。这张图是我用模拟器跑的一个demo,然后dump的一份hprof文件。这里打了个马赛克,让我们先暂且忽略它,后面再为大家揭晓。可以先告诉大家的是,这张图片的尺寸是700 * 1050。我们看到dump的信息中有一个变量叫做mBuffer,简单介绍一下。mBuffer就是一张bitmap开在java层的的内存的大小,你可以暂时简单理解成一张图片所占用的内存大小,为什么说暂时呢,因为其实应该是大于等于的,这设计到内存复用的逻辑。不过这不是我们这次分享的重点,暂且把它当作一张bitmap所占用的内存。放眼一望,可以看到这张图片占用了很大的内存,6615000字节,算了一下,也就是 700 * 1050 * 9,是我们刚才看到的图片尺寸的九倍!所以这个九倍是怎么来的呢?

我们了解到,每张图片都有自己不同的像素格式。Android支持四种格式,分别是ARGB_8888,ARGB_4444,RGB_565和APLHA_8。每个像素格式的区别如下表:

像素格式 单位像素字节数 备注
ARGB_8888 4 ARGB每个通道占8位,即每个像素点占32位
ARGB_4444 2 每个通道占4位,即每个像素点占16位
RGB_565 2 RGB三个通道分别占5、6、6位,即每个像素点占16位
ALPHA_8 1 仅alpha通道,占8位,即每个像素点占8位

每个原色都储存着所表示的颜色值,即位图数越高,所存储的颜色也就越丰富,也就是我们说的画质越高。所以我们认为,一张图片所占用的内存是由所有像素点所占有的字节大小决定的。即:

一张图片的内存 = 宽 * 高 * 单位像素字节数。

其中ARGB_4444已经在API 19及以上的版本废弃了,默认使用32位位图,而ALPHA_8最为特殊,适用场景不多,所以对于我们来说,最常用的就是ARGB_8888和RGB_565两种格式。按照我们的推算公式,ARGB_8888格式的图片应该会比RGB_565格式的图片内存大两倍。下面我们来实验下。

2.png

图中我们使用上述两种图片格式去加载了同一张图片(默认采用ARGB_8888格式),我们从log信息中可以清楚的看到,确实是程两倍关系。但是一定是两倍吗?

显然答案是否定的。不然我也就不会问这种问题了= =。我们来看下图:

3.png

先从结果上看,这次虽然采用的还是两种格式,但是加载出来的图片大小却是一样的。不知道有没有细心的小伙伴可以一眼看出这张图和上一张图的区别(不是image1变成image2了。。。),我们发现,这次加载的一张图片是png格式的。我们都知道,png格式是有透明度的图片,那么为什么使用一张png格式的图片。我们给图片设定的像素格式就没用了呢?

4.png

再看下我们刚才给图片设定像素格式的参数,“inPreferredConfig”。再结合下这个参数的注释,不难理解,这只是个“建议”。但是如果系统发现这张图片不匹配,比如我们上面的例子,他会自己选择一个最合适的像素格式来加载图片,也就说明了,并不是我们设定了像素格式就会有用的。

回到我们一开始的问题,我们得到的答案是9倍的关系,但是即使我们使用默认的ARGB_8888的像素格式,也只有4倍呀,那剩下的几倍在哪里呢?

5.png

回到我们最开始的那张图,我们把马赛克去掉,发现并不是我告诉你们的700 * 1050的尺寸。但是我并没有骗你们!那么为什么宽和高都被放大了呢?其实这个是因为有一个情况我没有告诉你们。上面测试的时候可以看到我把图片放在了xhdpi目录下,其实,我使用的模拟器试xxhdpi的,也就是480dpi,是xhdpi的1.5倍,系统会根据自己的位深去对应的目录去找资源,如果找不到的话会从其他的目录里找。我们放到xhdpi目录下的资源系统会认为那是属于xhdpi位深的,所以使用在xxhdpi下就会对其进行扩大。也就导致了宽和高分别被扩大了 480 / 320 即1.5倍,至此终于凑齐了我们开篇所抛下的问题,为什么是9倍的关系了(1.5 * 1.5 * 4)。

关于踩坑

现在我们了解到了一张bitmap可能会为我们带来如此巨大的内存开销,而在日常开发过程中,经常有人跟我们渗透“使用完bitmap要及时释放”的逻辑。我深深的记在心里,于是写出了下面的代码:

6.png

放眼望去可能没什么问题,先加载了一张图片A,然后通过一些变换得到了另外一张图片B,然后我及时的把A释放掉了!(快夸我!)

然而并没有如我们所愿,我在跑demo的时候崩溃了,于是我们看了下源码,找到了下面这一段。。。

7.png

我们可以看到,这里写着如果返回的bitmap与原来的一样的话,就会把我们传进去的A对象返回出来!所以其实我们上面的做法是不保险的,也就是存在A和B是同一个对象的可能!

再来看下面一段类似的代码:

8.png

因为踩过上一个坑,这次我机智的改变了他的高度,也就是不会返回给我同一个对象了。但是这次我换了取bitmap的方法,这样写有问题吗?当然有问题了,不然我拿出来干嘛。不过奇怪的是,我们这次第一次跑这段代码的时候是没有异常的,但是在第二次发生了崩溃!老话说得好,有问题,翻源码,机智的我又找到了下面这段代码:

9.png

恍然大悟,原来我们获取资源中的bitmap的时候,系统会为我们做一个缓存,也就是第二次开始所取出来的图片都是我们之前缓存的,而经过了我们第一次的释放后,缓存中的bitmap被释放掉了,也就不难解释为什么我们第二次取出来的bitmap再使用的时候会崩溃了。既然做了缓存,那么其实如果我们反复取这张图,内存是不会增长的,而使用BitmapFactory的方法内存是会一直增长的,有兴趣的小伙伴可以试一下。

至此这次分享的内容结束了,主要是想带大家来了解一下bitmap的一些知识,避免由于bitmap所带来一些内存上的问题,以后大家在处理内存优化的时候可以更加小心。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容