Moosphan/Android-Daily-Interview

2019-11-26:谈一谈Glide的缓存机制?

MoJieBlog opened this issue · 6 comments

2019-11-26:谈一谈Glide的缓存机制?
lvasd commented

郭霖大佬曾经基于glide 3.X版本 写过 7 8篇关于glide的博客 现在虽然glide 4.X了 但是很多东西还是没变的

twfx5 commented

Glide的缓存机制,主要分为2种缓存,一种是内存缓存,一种是磁盘缓存。
使用内存缓存的原因是:防止应用重复将图片读入到内存,造成内存资源浪费。
使用磁盘缓存的原因是:防止应用重复的从网络或者其他地方下载和读取数据。

具体来讲,缓存分为加载和存储:
①当加载一张图片的时候,获取顺序:Lru算法缓存-》弱引用缓存-》磁盘缓存(如果设置了的话)。

当想要加载某张图片时,先去LruCache中寻找图片,如果LruCache中有,则直接取出来使用,并将该图片放入WeakReference中,如果LruCache中没有,则去WeakReference中寻找,如果WeakReference中有,则从WeakReference中取出图片使用,如果WeakReference中也没有图片,则从磁盘缓存/网络中加载图片。

②将缓存图片的时候,写入顺序:弱引用缓存-》Lru算法缓存-》磁盘缓存中。

当图片不存在的时候,先从网络下载图片,然后将图片存入弱引用中,glide会采用一个acquired(int)变量用来记录图片被引用的次数, 当acquired变量大于0的时候,说明图片正在使用中,也就是将图片放到弱引用缓存当中;如果acquired变量等于0了,说明图片已经不再被使用了,那么此时会调用方法来释放资源,首先会将缓存图片从弱引用中移除,然后再将它put到LruResourceCache当中。这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。

另:从Glide4.x开始,读取图片的顺序有所改变:弱引用缓存-》Lru算法缓存-》磁盘缓存

那我来说说glide4 的缓存机制吧
glide4 缓存主要分为三个 activiteResources(弱引用缓存) MemoryCache(Lru缓存) DiskCache(磁盘缓存) 还有一个http网络缓存, 不多做介绍

首先弱引用缓存代表的是当前正在使用的缓存, 请求图片之后 会分为两个步骤, 1.进入磁盘缓存,2进入弱引用缓存。 在弱引用缓存中使用一个计数器来维护当前资源的是否被使用,如果计数器=0说明当前资源已经不被使用了,则进入Lru缓存,Lru缓存是glide使用linkhashmap来维护的,如果lru满了则删除最长时间未使用的。
如果一个资源加载的时候在弱引用缓存中找不到,就会到lru缓存中查找,如果没找到就去磁盘缓存找,不管在lru中找到 还是在磁盘中找到, 都会把命中的缓存,放在弱引用缓存中.

glide设计的三层缓存模型, 其中内存缓存 减轻了磁盘缓存的压力,避免io操作,而弱引用缓存则减轻了 lru缓存的压力,避免lru过满导致频繁gc,并且提高查找效率

另外再说下 glide4 五种缓存策略 data source all no automic
data则是缓存住原始图片资源, source则是缓存住变换后的资源(glide 会针对imageview的大小对图片预先变换,避免小imageview加载大图片浪费内存)
all 就是两种都缓存, no就是不缓存 ,automiic 则比较特殊,会缓存data 根据图片的编码 自行判断是否缓存resource

yline commented

配上代码来说,统一的key,依据key去找;代码在Engine中
1,Hashmap<Key, ResourceWeakReference>,从弱引用中获取,直接内存缓存。系统内存不足时,允许gc
2,Lrucache<Key, Resource>,Lrucache缓存,超过缓存额度时,将最久未使用的内存删除。使用内存缓存,强引用
3,Hashmap<Key, EngineJob>,从网络中获取图片,同时如果多个相同的图片请求触发,避免相同的网络重复请求
4,创建新的LoadStatus(cb, EngineJob),从网络中获取图片

总结:弱引用 -> Lrucache -> 网络防重复请求 -> 网络请求

1,为什么使用Glide
Glide可以处理多种图片格式缓存 如:gif jpg png webp 缩略图
Glide使用了三种缓存机制 活动缓存(HashMap软引用) 内存缓存(LruCache)硬盘缓存(DiskLruCache)
Glide创建一个空的Fragment 来做生命周期管理 防止内存溢出
Glide缓存机制
加载图片通过算法生成key先去活动缓存获取 如果活动缓存有就直接显示 没有就去内存缓存中去寻找 内存中如果有移除内存中缓存添加到活动缓存中展示 内存缓存如果没有则去磁盘缓存中 磁盘缓存中有添加到活动缓存中显示 磁盘缓存中没有直接去网络中下载 网络中下载完成展示图片并缓存到硬盘缓存中 Glide创建一个空的Fragment来管理生命周期 如果Activity被关闭把活动缓存的添加到内存缓存中 活动缓存满的话未被使用的缓存移动到内存缓存中

1,为什么使用Glide
Glide可以处理多种图片格式缓存 如:gif jpg png webp 缩略图
Glide使用了三种缓存机制 活动缓存(HashMap软引用) 内存缓存(LruCache LinkedHashMap强引用)硬盘缓存(DiskLruCache)
Glide创建一个空的Fragment 来做生命周期管理 防止内存溢出
Glide缓存机制
活动缓存(HashMap软引用) -》内存缓存(LruCache LinkedHashMap强引用)-》硬盘缓存(DiskLruCache)-》外置加载(网络,IO流)
加载图片通过算法生成key先去活动缓存获取 如果活动缓存有就直接显示 没有就去内存缓存中去寻找 内存中如果有移除内存中缓存添加到活动缓存中展示 内存缓存如果没有则去磁盘缓存中 磁盘缓存中有添加到活动缓存中显示 磁盘缓存中没有直接去网络中下载 网络中下载完成展示图片并缓存到硬盘缓存中 Glide创建一个空的Fragment来管理生命周期 如果Activity被关闭把活动缓存的添加到内存缓存中 活动缓存满的话未被使用的缓存移动到内存缓存中