在 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。

它的核心特点是:

特点

说明

正在使用

图片正在被某个 Target 或 ImageView 使用

不能随便回收

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

不参与 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:负责空闲复用

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


十二、总结

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

一句话总结:

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

再简单一点:

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

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

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

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