Glide图片内存优化分析

来源:互联网 发布:大数据价值 编辑:程序博客网 时间:2024/06/05 08:31

本来想直接聊图片加载优化,仔细想了想,发现这是个太大的话题。所以就分拆下,一部分一部分的来聊这个话题,今天说说Glide的图片内存优化

图片中内存的处理是块很值得深入研究的内容,涉及到的难点也有多。

首先,内存总量有限,必须限制图片加载的内存

弱引用

这个大家都懂,好多第三方加载组件也体现了这个思路。

最早,大家将Bitmap用 弱引用 管理起来,当内存不足时,系统会自动GC回收掉部分引用,从而达到内存管理的目的。 这种方式很简单,组件本身不管理图片内存,而是交给GC,有GC来自动回收内存。

这种方法会有几个 问题 :

  1. 应用占有的内存量会不断攀升,知道内存不足时,出现断崖时的内存回收
  2. GC的时间可能会比较长,造成界面会有明显的卡顿。
  3. GC回收的内存,没有区分,可能回收了最近在使用的Bitmap,造成二次加载。
  4. 最严重的,新的Android系统开始每次GC都会回收弱引用,这就使内存缓存没有用处。

强引用+LRU算法

基于以上问题,有些组件开始用 强引用+LRU算法 的方式处理图片加载的问题,其思路大概是:

给定一个固定图片缓存大小,将所有的使用的Bitmap用强引用的方式管理起来,并利用LRU算法,将旧的Bitmap释放,新的bitmap增加。

这样,图片缓存不会无限制的增长,内存量也能处在一个较理想的范围,申请和释放。UIL就是采用这种方法。

但这个思路也会有 问题 :

图片缓存的内存不会无限制增长,但会周期性的释放和申请。特别是对于一个长列表页面,图片会不断的申请,不断的释放。因为最终的内存释放还是GC去处理,快速滑动时,会造成大量的图片申请内存,大量的图片释放,系统的GC会很频繁,就产生了所谓的 内存抖动 。

内存的抖动同样也会造成界面卡顿,在快速滑动时,会非常明显。

提到界面卡顿,我要说明下 卡顿的原因 。

人眼能识别的帧数是一秒24帧,就是所若一个屏幕以每秒24帧显示时,人眼是看不出什么的,感觉很流畅。但若少于24帧,我们就能感觉出卡顿,不流畅。 最佳的帧数是每秒60帧,再高就没有任何意义了,一般显卡会跟屏幕的刷新速率保持一致,大部分都是60hz。

那我们来计算下,最高60帧,1000ms/60帧=16ms/帧,最低24帧,1000ms/24帧=42ms,也就是说每次ui线程里面的计算最佳的情况是少于16ms,最高则不能超过42ms。

以ListView为例,getView的运行时间不能大于42ms, 推荐大家用 hugo 统计运行时间,很方便。

特殊情况下,即便是不大于42ms,接近也会造成卡顿,因为还会有其他的函数运行。

在这种情况下,若出现内存抖动,就会频繁的暂停进程,释放内存,极易出现卡顿。

GLide的BitmapPool

Glide对这个环节做了非常好的优化,解决了内存抖动的问题。

Glide构建了一个BitmapPool,Bitmap申请和回收都是透过BitmapPool来处理的。新加载图片时,会先从BitmapPool里面找有没有相应大小的Bitmap,有则直接使用,没有才会申请新的Bitmap;回收时,则会提交给BitmapPool, 供下次使用。

这种方式极大的减少了Bitmap的申请和回收操作,使得GC频度降低了很多。

图片与显示区域大小一致

图片加载最终的目的是显示到界面上,因此若是图片缓存的尺寸大于显示区域的尺寸是没有必要的。不光是造成内存浪费,占用较大的内存,而且会造成图片解析速度比较慢。

因此,不管是UIL,Glide和Freso等等都建议ImageView需要给定固定的长和宽,这样图片加载时,就可以根据显示区域的大小,加载最小的图片,又不会造成损失。

另外,七牛的云服务提供了imageView2参数,可以给定长宽,在网络加载层次上就可以降低加载的图片尺寸,提高加载速度。

另外,UIL,Glide都将缩放后的图片缓存到本地,下次加载时直接从磁盘缓存加载,也会有比原始尺寸加载更好的速度。

图片的加载优化有很多内容可以做,比如现在的图片加载,都是等将要显示时开始加载,这样图片可能需要等待一下才能加载出来,我们是不是可以提前加载呢?

0 0
原创粉丝点击