在 Glide 的图片加载流程中,内存缓存并不是只有一个简单的 LruCache。Glide 会把内存中的资源分成两类:

正在使用的资源:ActiveResources
最近用过但当前没人使用的资源:LruResourceCache

所以 Glide 查询缓存的大致顺序是:

ActiveResources
    ↓
LruResourceCache / MemoryCache
    ↓
Resource Disk Cache
    ↓
Data Disk Cache
    ↓
原始数据源

也就是说,Glide 会优先判断这张图片是不是已经在某个 ImageView 上显示;如果没有,再去内存 LRU 缓存里找。


一、ActiveResources 是什么?

ActiveResources 可以理解为:

当前正在被页面使用的图片资源集合。

比如:

Glide.with(context)
    .load(url)
    .into(imageView)

当图片加载完成,并且正在 ImageView 上显示时,这个资源就属于 active resource。

它的核心特点是:

特点

说明

正在使用

图片正在被某个 TargetImageView 使用

不能随便回收

否则页面上正在显示的图片可能出问题

不参与 LRU 淘汰

它不是“可淘汰缓存”,而是“正在使用的资源”

可以被多个请求复用

多个相同请求可以直接复用同一个 active resource

简单来说:

ActiveResources = 正在显示中的图片

它更像是一个“正在使用资源登记表”,而不是传统意义上的缓存。


二、LruResourceCache 是什么?

LruResourceCache 是 Glide 内存缓存中的 LRU 缓存实现。

它可以理解为:

最近使用过,但当前没有被页面使用的图片资源缓存。

比如一个页面显示过某张图片,后来这个页面退出了,或者 ImageView 被复用了,这张图片不再被任何地方显示。

如果这张图片允许被内存缓存,Glide 就会把它放入 LruResourceCache,方便下次快速复用。

它的特点是:

特点

说明

当前没人使用

不再被 ImageView 显示

可以被复用

下次加载相同图片时可以直接命中

受内存大小限制

超过最大容量后会淘汰旧资源

使用 LRU 策略

最近最少使用的资源会优先被移除

简单来说:

LruResourceCache = 最近用过、当前空闲、可以复用的图片

三、为什么有了 LruResourceCache,还需要 ActiveResources?

核心原因是:

LruResourceCache 管的是“空闲资源”,ActiveResources 管的是“正在使用的资源”。

它们解决的问题不一样。


四、问题一:正在显示的图片不能被 LRU 淘汰

假设 Glide 只有 LruResourceCache,那么正在显示的图片也放在 LRU 缓存里。

这时可能会出现这种情况:

ImageView 正在显示 Bitmap
        ↓
Bitmap 同时也在 LruResourceCache 中
        ↓
内存紧张,LRU 开始淘汰资源
        ↓
正在显示的 Bitmap 被回收
        ↓
ImageView 继续使用这个 Bitmap
        ↓
可能出现显示异常,甚至 recycled bitmap 相关错误

这显然是不安全的。

所以 Glide 把正在使用的资源从 LRU 缓存中独立出来,放到 ActiveResources 中管理。

这样就可以保证:

正在显示的图片不会被 LRU 策略误删

五、问题二:LRU 缓存只应该管理“没人用的资源”

LRU 的核心思想是:

缓存空间有限,最近最少使用的资源可以被淘汰

但是 active resource 不是“可以淘汰的缓存”,而是“业务正在使用的资源”。

这两者的语义完全不同。

可以用一个生活中的例子理解:

ActiveResources = 正在桌上吃的菜
LruResourceCache = 冰箱里的剩菜

冰箱里的剩菜可以清理,但是别人正在吃的菜不能直接拿走。

同理:

LruResourceCache 可以淘汰
ActiveResources 不能随便淘汰

六、问题三:同一张图片正在显示时,可以直接复用

假设两个 ImageView 同时加载同一张图片:

Glide.with(context)
    .load(url)
    .into(imageView1)

Glide.with(context)
    .load(url)
    .into(imageView2)

如果 imageView1 已经显示了这张图片,那么 imageView2 再加载同一个 URL 时,Glide 会优先从 ActiveResources 中查找。

如果命中,Glide 就可以直接复用这份正在使用的资源,而不需要:

重新解码
重新从内存 LRU 中取
重新从磁盘读取
重新请求网络

这可以减少重复加载,提高性能。


七、ActiveResources 和 LruResourceCache 的流转过程

一张图片在内存中的生命周期大致如下:

图片加载完成
    ↓
放入 ActiveResources
    ↓
ImageView 正在显示
    ↓
页面销毁 / View 被复用 / Request 被 clear
    ↓
资源 release
    ↓
如果允许内存缓存
    ↓
放入 LruResourceCache
    ↓
下次再次加载相同图片
    ↓
从 LruResourceCache 中取出
    ↓
重新放回 ActiveResources

可以画成这样:

加载完成
   ↓
ActiveResources
   ↓  release
LruResourceCache
   ↓  再次被使用
ActiveResources

也就是说:

ActiveResources 和 LruResourceCache 不是互相替代关系
而是资源在不同状态下的两个管理位置

八、Glide 内部的大致查询逻辑

Glide 加载图片时,内存查询逻辑可以简化为:

先查 ActiveResources
    如果命中,直接返回正在使用的资源

否则查 LruResourceCache
    如果命中,把资源从 LRU 缓存中取出
    然后重新放入 ActiveResources

否则继续查磁盘缓存或原始数据源

伪代码可以这样理解:

fun loadFromMemory(key: Key): Resource? {
    // 1. 先查正在使用的资源
    val active = activeResources[key]
    if (active != null) {
        active.acquire()
        return active
    }

    // 2. 再查 LRU 内存缓存
    val cached = memoryCache.remove(key)
    if (cached != null) {
        cached.acquire()
        activeResources.activate(key, cached)
        return cached
    }

    // 3. 内存没有命中,继续走磁盘或网络
    return null
}

注意这里有一个关键点:

从 LruResourceCache 命中的资源,会重新变成 active resource

因为它又被页面使用了。


九、release 之后资源去哪?

ImageView 不再使用这张图片时,比如:

Glide.with(context).clear(imageView)

或者页面生命周期结束,Glide 会释放对应的资源。

释放之后大致有两种情况:

如果资源允许内存缓存
    → 放入 LruResourceCache

如果资源不允许内存缓存
    → 回收资源

可以理解为:

正在用的时候:ActiveResources
不用但还能复用:LruResourceCache
不能复用:回收

十、ActiveResources 和 LruResourceCache 的区别

对比项

ActiveResources

LruResourceCache

保存内容

正在使用的资源

最近用过但当前没人用的资源

是否正在显示

是否可以淘汰

不应该被 LRU 淘汰

可以被 LRU 淘汰

是否受 LRU 策略控制

主要作用

保护正在使用的资源,并支持复用

缓存空闲资源,提升下次加载速度

典型状态

ImageView 正在显示

页面退出、View 复用后暂存

再次加载时

优先命中

次优先命中


十一、为什么不直接都放进 LruResourceCache?

因为这样会混淆两种资源状态:

正在使用的资源
空闲等待复用的资源

如果全部放到 LRU 中,会带来两个问题:

第一,正在显示的图片可能被 LRU 淘汰,导致显示异常。

第二,LRU 缓存中既有正在使用的资源,又有空闲资源,缓存淘汰逻辑会变得不清晰。

所以 Glide 选择把它们拆开:

ActiveResources:负责正在使用
LruResourceCache:负责空闲复用

这样职责更清楚,也更安全。


十二、总结

ActiveResourcesLruResourceCache 都属于 Glide 的内存缓存体系,但它们不是同一个东西。

一句话总结:

ActiveResources 管正在使用的图片;
LruResourceCache 管暂时不用但可能马上复用的图片。

再简单一点:

ActiveResources = 使用中
LruResourceCache = 待复用
DiskCache = 持久复用
Source = 重新加载

所以 Glide 之所以需要 ActiveResources,并不是因为 LruResourceCache 不够用,而是因为:

正在使用的资源不能按照 LRU 规则随便淘汰

这就是 Glide 内存缓存设计中 ActiveResources 存在的核心意义。