Android系统Bitmap内存分配原理与优化(转)
一、前言
笔者最近致力于vivo游戏中心稳定性维护,在分析线上异常时,发现有相当一部分是由OutOfMemory引起。谈及OOM,我们一般都会想到内存泄漏,其实,往往还有另外一个因素——图片,如果对图片使用不当的话,很容易吃掉大量内存,从而导致异常。
尤其是游戏中心在2020末~2021初的几个重要版本,上线了很多内容相关的feature,引入大量图片、视频列表,从而导致线上OOM占比上升。
在这篇文章中,笔者将讲解一张看似普通的Bitmap对内存的占用,介绍Android Studio中帮助我们分析图片占用内存的工具,举例说明流行的两大图片加载框架:Glide、Picasso在加载图片时使用内存的不同方式,接着分析不同drawable目录下图片的显示策略,最后基于手机内存、版本,提出一种优化内存分配的方案。
二、查看图片内存占用
一张图片在内存占用的空间究竟有多少,普遍存在的一个误解是,图片本身在磁盘上/从网络下载下来是多大,就会占用多少的内存。这种说法是不正确的,图片占用内存的大小不取决于它本身的大小,而取决于图片库所采用的展示方式所申请的内存。
拿钢铁侠这张图片举例,它的尺寸是350*350,可以看到在电脑磁盘上,它只占36KB的空间。
modb_20210701_4d88f4da-da01-11eb-b2db-38f9d3cd240d.png
省略N多字。。。。。。。。
文章有点长,有兴趣的去看原文,下面只转载优化的部分:
五、优化策略
在实际的开发中,我们希望中高端机型加载更清晰的图片(ARGB_8888),以提升用户体验,对于低端机型则希望加载占用内存更小的图片(RGB_565),以降低OOM发生的概率。可以在初始化Glide时进行这样的配置。需要留意的是不要对含透明区域的图片采用这种优化方案。
@GlideModule
class MyGlideModule : AppGlideModule() {
override fun applyOptions(context: Context, builder: GlideBuilder) {
builder.setDefaultRequestOptions(RequestOptions().format(getBitmapQuality()))
}
private fun getBitmapQuality(): DecodeFormat {
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || hasLowRam()) {
// 低端机型采用RGB_565以节约内存
DecodeFormat.PREFER_RGB_565
} else {
DecodeFormat.PREFER_ARGB_8888
}
}
}
六、小结
借助一些开源工具,我们可以便捷地定位大图,如滴滴开源的DoKit,篇幅原因不进行详细介绍。最后,对于我们日常开发总结几点建议,希望大家的应用稳定性节节攀升。
-
在多图的场景(比如RecyclerView)注意及时释放图片资源;
-
使用占据内存更小的图片格式;
-
图片源文件尺寸应当与目标ImageView相近;
-
优先满足xxhdpi、xxxhdpi的图片资源需求;
-
根据设备性能,采用不同的图片加载策略。