千家信息网

63.ImageLoader源代码分析-内存缓存算法

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,一. 前言图片内存缓存可以提高图片显示速度,但是有些问题,比如占用内存,如果不加以控制,甚至可能会OOM所以,需要提供各种各样的算法来控制内存的使用,以适应不同的使用场景,目前,ImageLoader
千家信息网最后更新 2026年11月02日63.ImageLoader源代码分析-内存缓存算法

一. 前言

图片内存缓存可以提高图片显示速度,但是有些问题,比如占用内存,如果不加以控制,甚至可能会OOM

所以,需要提供各种各样的算法来控制内存的使用,以适应不同的使用场景,目前,ImageLoader提供了若干内存管理算法。

默认内存缓存是关闭的,需要手动打开

二. 继承关系图

三. 主要内存算法介绍

算法解释
MemoryCacheInterface 内存缓存的接口
MemoryCacheInterface 内存缓存的接口
FuzzyKeyMemoryCache模糊Key内存缓存,一些不同的Key可能会被认为是相同(通过equals方法)。当你put一个值到cache里面时,equals相同的Key也会被替换。这是一个内部功能,通常我们不需要使用到它。
LimitedAgeMemoryCache限制时间内存缓存,如果一些对象的使用时间超过了定义的值,那么就会移除。比如最大时间设置成60s,那么如果一个对象是60s前put进来的,那么它就会失效。
LruMemoryCache一个强引用的图片,限制图片使用数量的内存缓存,每个被访问的图片都会移动到队列的头部。当一个图片添加到一个满的队列的时候,队尾的图片将会被驱逐而被垃圾回收器回收。
BaseMemoryCache抽象类,基本的图片缓存管理,提供了图片存储(强引用或者弱引用),具体的可以看下面的MemoryCache实现。
WeakMemoryCache继承自BaseMemoryCache,弱引用内存缓存,弱引用,当内存不足的时候,会被系统回收。
LimitedMemoryCache抽象类,继承自BaseMemoryCache,限制内存的内存管理抽象类,包括下面4个具体实现。提供图片对象存储,存储的所有的图片大小将不会超过大小限制。这个缓存提供了强引用和弱引用存储了图片,强引用用来限制图片大小,弱引用用来其他缓存的图片。
FIFOLimitedMemoryCache继承自LimitedMemoryCache,存储的图片大小不小超过限定的大小。当缓存图片到达指定大小时,会按照FIFO(先进先出)的原则清理图片。
LRULimitedMemoryCache继承自LimitedMemoryCache,存储的图片大小不小超过限定的大小。当缓存图片到达指定大小时,最早使用的图片会从缓存中删除。
LargestLimitedMemoryCache继承自LimitedMemoryCache,存储的图片大小不小超过限定的大小。当缓存图片到达指定大小时,最大的图片会从缓存中删除。
UsingFreqLimitedMemoryCache继承自LimitedMemoryCache,存储的图片大小不小超过限定的大小。当缓存图片到达指定大小时,最少使用频率的图片会从缓存中删除。

下面,我们会具体看各个MemoryCache的实现

四. LimitedAgeMemoryCache

public class LimitedAgeMemoryCache implements MemoryCache {    private final MemoryCache cache;    private final long maxAge;    private final Map loadingDates = Collections.synchronizedMap(new HashMap());    @Override    public boolean put(String key, Bitmap value) {        boolean putSuccesfully = cache.put(key, value);        if (putSuccesfully) {            loadingDates.put(key, System.currentTimeMillis());        }        return putSuccesfully;    }    @Override    public Bitmap get(String key) {        Long loadingDate = loadingDates.get(key);        if (loadingDate != null && System.currentTimeMillis() - loadingDate > maxAge) {            cache.remove(key);            loadingDates.remove(key);        }        return cache.get(key);    }}   

实现的方法很简单,在put的时候,用一个Map记录了存入的时间,get的时候,判断时间是否大于maxAge,如果是,那么就删掉这个缓存。

五. LruMemoryCache

public class LruMemoryCache implements MemoryCache {    private final LinkedHashMap map;    private final int maxSize;    @Override    public final boolean put(String key, Bitmap value) {        ...        synchronized (this) {            size += sizeOf(key, value);            Bitmap previous = map.put(key, value);            if (previous != null) {                size -= sizeOf(key, previous);            }        }        trimToSize(maxSize);        return true;    }    private void trimToSize(int maxSize) {        while (true) {            String key;            Bitmap value;            synchronized (this) {                if (size < 0 || (map.isEmpty() && size != 0)) {                    throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");                }                if (size <= maxSize || map.isEmpty()) {                    break;                }                Map.Entry toEvict = map.entrySet().iterator().next();                if (toEvict == null) {                    break;                }                key = toEvict.getKey();                value = toEvict.getValue();                map.remove(key);                size -= sizeOf(key, value);            }        }    }}   

实现的原理是利用LinkedHashMap,先存入的key在遍历的时候在链表的头部,所以在put值的时候,从头开始遍历HashMap,从头删除图片缓存,直到内存的大小在指定大小以内。

另外为了防止多线程的问题,put和trimToSize删除图片的时候做了synchronized同步。

这个也是ImageLoader使用比较多的一种内存管理方法。

六. WeakMemoryCache

public class WeakMemoryCache extends BaseMemoryCache {   @Override   protected Reference createReference(Bitmap value) {      return new WeakReference(value);   }}

实现方法很简单,用一个弱引用就可以解决,用弱引用包裹了图片。

七. FIFOLimitedMemoryCache

FIFOLimitedMemoryCache继承自抽象类LimitedMemoryCache,所以看算法实现前还要看LimitedMemoryCache代码。

抽象类LimitedMemoryCache和其实现子类的关系是LimitedMemoryCache put的时候限定超过大小时调用removeNext删除图片缓存;

但是具体怎么删,删除什么图片缓存,就由子类实现。

public abstract class LimitedMemoryCache extends BaseMemoryCache {   @Override   public boolean put(String key, Bitmap value) {      boolean putSuccessfully = false;      // Try to add value to hard cache      int valueSize = getSize(value);      int sizeLimit = getSizeLimit();      int curCacheSize = cacheSize.get();      if (valueSize < sizeLimit) {         while (curCacheSize + valueSize > sizeLimit) {            Bitmap removedValue = removeNext();            if (hardCache.remove(removedValue)) {               curCacheSize = cacheSize.addAndGet(-getSize(removedValue));            }         }         hardCache.add(value);         cacheSize.addAndGet(valueSize);         putSuccessfully = true;      }      // Add value to soft cache      super.put(key, value);      return putSuccessfully;   }}   public class FIFOLimitedMemoryCache extends LimitedMemoryCache {    private final List queue = Collections.synchronizedList(new LinkedList());   ...   @Override   protected Bitmap removeNext() {      return queue.remove(0);   }}

用list实现,直接从头开始移除。

八. LRULimitedMemoryCache

public class LRULimitedMemoryCache extends LimitedMemoryCache {   /** Cache providing Least-Recently-Used logic */   private final Map lruCache = Collections.synchronizedMap(new LinkedHashMap(INITIAL_CAPACITY, LOAD_FACTOR, true));   @Override   protected Bitmap removeNext() {      Bitmap mostLongUsedValue = null;      synchronized (lruCache) {         Iterator> it = lruCache.entrySet().iterator();         if (it.hasNext()) {            Entry entry = it.next();            mostLongUsedValue = entry.getValue();            it.remove();         }      }      return mostLongUsedValue;   }}

使用一个 LinkedHashMap lruCache来保存图片的put顺序,需要移除的时候(removeNext)从lruCache找到第一张图片即可。

九. UsingFreqLimitedMemoryCache

public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {   private final Map usingCounts = Collections.synchronizedMap(new HashMap());   @Override   public Bitmap get(String key) {      Bitmap value = super.get(key);      // Increment usage count for value if value is contained in hardCahe      if (value != null) {         Integer usageCount = usingCounts.get(value);         if (usageCount != null) {            usingCounts.put(value, usageCount + 1);         }      }      return value;   }   @Override   protected Bitmap removeNext() {      Integer minUsageCount = null;      Bitmap leastUsedValue = null;      Set> entries = usingCounts.entrySet();      synchronized (usingCounts) {         for (Entry entry : entries) {            if (leastUsedValue == null) {               leastUsedValue = entry.getKey();               minUsageCount = entry.getValue();            } else {               Integer lastValueUsage = entry.getValue();               if (lastValueUsage < minUsageCount) {                  minUsageCount = lastValueUsage;                  leastUsedValue = entry.getKey();               }            }         }      }      usingCounts.remove(leastUsedValue);      return leastUsedValue;   }}

使用一个HashMap usingCounts来存储bitmap的使用次数,每次get的时候都会让使用次数+1,那需要移除的时候图片缓存的时候,遍历usingCounts,找到使用次数最少的图片,删除之。

不过这种遍历的算法感觉效率不高,慎用!

图片 缓存 大小 内存 时候 存储 算法 时间 限制 方法 管理 从头 对象 次数 不同 最大 相同 头部 子类 接口 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 华服互联网科技靠谱吗 天津市摩尔互联网科技 朗新科技与工业互联网 中资互联网科技 鑫亿盛互联网科技 互联网女皇 腾讯科技 互联网科技视频素材 山东吉时兔互联网科技有限公司 中国互联网有什么科技含量 以后互联网后是啥科技 科技互联网大厂 赶超互联网科技 微信多开 互联网科技产业特征 洛阳共同富裕互联网科技有限公司 有人说阿里系是互联网科技企业 2021世界互联网领先科技成果发布 昆明中奇联合互联网科技 好易买互联网科技 数字科技和互联网金融哪个好 平安好医生打造互联网科技医疗 互联网科技股票 互联网科技缩写 滨湖区互联网智能科技产品供应 北京三清互联网科技 移动互联网科技股 互联网科技产业特征 米聚互联网科技南京有限公司排面 玉溪新华互联网科技好不好 滨湖区互联网智能科技产品有哪些 工业互联网科技成果转化
0