Bitmap的内存占用和Bitmap加载优化

Bitmap的内存占用和Bitmap加载优化,第1张

内存占用

首先要清楚Bitmap的文件大小肯定不是实际的内存加载大小。因为文件只是存储的信息,加载到内存中显示出来时还需要经过转换。

获取运行的时的内存占用: 

针对Bitmap位图对象,Android的系统框架中的graphics包下的Bitmap类。有bitmapgetByteCount()方法获取内存大小,单位字节(byte) 

其实本质上Bitmap的内存占用计算非常简单:

基本公式:总内存=宽×高×色彩空间

但是在实际运行中不是这么简单,公式的每个参数都会有被不同因素影响。

影响内存大小的三要素

1 宽高:这个不用解释

2 色彩空间 :即BitmapConfig枚举:ARGB_8888:总共32位(4byte),分别对应4个数值,数值单位为8bit位=1byte字节,分别描述透明度(1个)+RGB通道(3个)。每个字节数值范围0-255。作为Bitmap配置色彩空间的默认值。BitmapFactory加载时默认。 

public BitmapConfig inPreferredConfig = BitmapConfigARGB_8888

RGB_565

总共16位(2byte),分别对应3个数值,5位(红)+6位(绿)+5位(蓝)分别描述RGB通道。Glide加载时默认使用,DecodeFormat类 

public static final DecodeFormat DEFAULT = PREFER_RGB_565

可以看到,RGB_565只需要ARGB_8888的一半大小,代价是没有透明度描述。

3 缩放比 :对原始宽高的缩放设置认定为缩放比。

主动设置:

在解析Bitmap时,有个可选的Options对象,其中inSampleSize参数可以影响缩放比的结果。当使用该参数值时要求大于1且是2的倍数,比如在inSampleSize=2时,缩放比被缩小2倍(该功能只有缩小没有放大的可能),即“缩放比=原始缩放比×(1/2)”。对内存结果的影响是缩小4倍,因为宽/高都被缩小2倍。该值默认不生效,需要手动设置。

被动设置:

在系统中主要由,具体运行设备dpi的和文件存储的drawable文件dpi层级决定。 首先要引出屏幕密度概念。这是Android为应对众多的不同的屏幕分辨率色设备提出的概念和单位。

drawable文件的dpi层级:在Drawable系列文件中保存的Bitmap位图文件。根据Android开发的规范,Drawable的系列文件中的修饰符后命名是有意义的,声明了这个文件所属的Dpi(屏幕密度)层级。文件众多也对应了众多的Android设备屏幕密度。

设备的dpi层级:参考 materialio/devices/ 可以了解。

设备和drawable文件的dpi缩放比计算: 

比如drawable-xhdpi(320=2160=2mdpi)下的bitmap被加载到xxxhdpi(640=4160=4mdpi)的Pixel-XL中。 

dpi缩放比=设备dpi/drawable的dpi,所以上面的,dpi缩放比=640/320=2。 

实际意义就是在高分辨率的xxxhdpi设备中,drawable-xhdpi文件需要放大2倍,即宽高各放大2倍来适应高密度设备。(假设没有缩放就会图小控件大)。需要指出的是如果Bitmap文件保存在drawable没有后缀的文件中,系统会使用drawable的dpi默认值就是160;

最终公式

基于以上认识,丰富上文的基本公式,可以的得到最终的计算Bitmap内存公式

最终公式:总内存=(原始宽×缩放比)×(原始高×缩放比)×色彩空间

举个例子:

原图:1000宽X447高,位于drawable-xxhdpi(480dpi=3160dpi)文件包,设备Pixel-XL(560dpi=35160dpi)。主动设置inSampleSize=2。使用默认BitmapConfig=ARGB_8888

缩放比=主动设置×被动设置=1/2×(560/480)=05×1166=05833

色彩空间=ARGB_8888=32bit=4byte

原始大小=1000×447

内存占用=(原始宽×缩放比)×(原始高×缩放比)×色彩空间 

=1000×05833×447×05833×4 

=583×260×4 

=606320byte 

≈0578MB

启示

理解Bitmap的最终内存占用计算原理和内存占用各个参数,我们对Bitmap的处理时就有具体的目标。比如常见的优化Bitmap加载过程,其实就是对Bitmap加载时的各个变量参数设置修改。 常见的Bitmap优化:

修改缩放比:目标是修改最终加载的宽高,进而优化内存占用。具体就是设置inSampleSize值,如在适当的View上缩放显示适合的bitmap,实现bitmap的高效加载(Glide框架就是这样,让显示组件View的宽高的参与缩放比计算)。

修改色彩空间:在明确的不需要透明度的情况,使用RGB_565替换ARGB_8888,可以直接达到内存缩小一半的功效。缺点就是有限定条件。(从网络上的博文描述,不推荐使用ARGB_4444替换,因为这样的质量太差)

转自:>

如果需要直接 *** 作,可以使用

BitmapData,大约是

BitmapData bmpData = bmpLock()

参数有说明,这个是吧直接锁住,并且得到BitmapData,可以使用他的成员scan0来得到地址,用来做高效的运算

BitmapgetAllocationByteCount() 方法获取 Bitmap 占用的字节大小

默认情况下 BitmapFactory 使用 BitmapConfigARGB_8888 的存储方式来加载内容,而在这种存储模式下,每一个像素需要占用 4 个字节。

实际上 BitmapFactory 在解析的过程中,会根据当前设备屏幕密度和所在的 drawable 目录来做一个对比,根据这个对比值进行缩放 *** 作。

在 Android 中,各个 drawable 目录对应的屏幕密度分别为下:

PS: OptionsinMutable 置为 true,这里如果不置为 true 的话,BitmapFactory 将不会重复利用 Bitmap 内存

复用 inBitmap 之前,需要调用 canUseForInBitmap 方法来判断 reuseBitmap 是否可以被复用。这是因为 Bitmap 的复用有一定的限制:

在不压缩的前提下,不建议一次性将整张图加载到内存,而是采用分片加载的方式来显示部分内容,然后根据手势 *** 作,放大缩小或者移动显示区域。

BitmapRegionDecoder 将加载到内存中,可以以绝对路径、文件描述符、输入流的方式传递给 BitmapRegionDecoder

当需要在界面上同时展示一大堆的时候,比如 ListView、RecyclerView 等,由于用户不断地上下滑动,某个 Bitmap 可能会被短时间内加载并销毁多次。这种情况下通过使用适当的缓存,可以有效地减缓 GC 频率保证加载效率,提高界面的响应速度和流畅性。

LruCache(Least Recently Used)算法的核心思想就是 最近最少使用算法

内部维护了一个 LinkHashMap 的链表,通过put数据的时候判断是否内存已经满了,如果满了,则将最近最少使用的数据给剔除掉,从而达到内存不会爆满的状态。

以上就是关于Bitmap的内存占用和Bitmap加载优化全部的内容,包括:Bitmap的内存占用和Bitmap加载优化、BitMap 转 byte[]、C# 如何将Bitmap转换为byte[ ]类型的等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9315902.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存