深入解析开源项目之Universal-Image-Loader(二)内存---缓存篇

简介:

Universal-Image-Loader 是一个优秀的图片加载开源项目,Github地址在 (Github地址) ,很多童鞋都在自己的项目中用到了。优秀的项目从来都是把简单留给开发者,把复杂封装在框架内部。ImageLoader作为Github上Star数过万的项目,备受开发者青睐,所以我们有必要搞清楚它的内部实现。

在上一篇博客中我们分析了ImageLoader框架的整体实现原理,还没有看过的直接到 深入解析开源项目之ImageLoader(一)框架篇 。


ImageLoader之内存缓存

项目截图:

MemeryCache关系图

由上图我们可以看出:

MemoryCache

复制代码
package com.nostra13.universalimageloader.cache.memory;
import android.graphics.Bitmap;
import java.util.Collection;
public interface MemoryCache {
    boolean put(String key, Bitmap value);

    Bitmap get(String key);

    Bitmap remove(String key);

    Collection<String> keys();

    void clear();
   }
复制代码

BaseMemoryCache,LimitedAgeMemoryCache,LruMemoryCache,FuzzyKeyMemoryCache

复制代码
public abstract class BaseMemoryCache implements MemoryCache {

    private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());

    @Override
    public Bitmap get(String key) {
        Bitmap result = null;
        Reference<Bitmap> reference = softMap.get(key);
        if (reference != null) {
            result = reference.get();
        }
        return result;
    }

    @Override
    public boolean put(String key, Bitmap value) {
        softMap.put(key, createReference(value));
        return true;
    }

    @Override
    public Bitmap remove(String key) {
        Reference<Bitmap> bmpRef = softMap.remove(key);
        return bmpRef == null ? null : bmpRef.get();
    }

    @Override
    public Collection<String> keys() {
        synchronized (softMap) {
            return new HashSet<String>(softMap.keySet());
        }
    }

    @Override
    public void clear() {
        softMap.clear();
    }

    protected abstract Reference<Bitmap> createReference(Bitmap value);
}
复制代码
复制代码
public class LimitedAgeMemoryCache implements MemoryCache {//也是对MemoryCache的装饰

    private final MemoryCache cache;

    private final long maxAge;
    private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>());

    public LimitedAgeMemoryCache(MemoryCache cache, long maxAge) {
        this.cache = cache;
        this.maxAge = maxAge * 1000; // to milliseconds
    }

    @Override
    public boolean put(String key, Bitmap value) {//时间超过我们设定的值,将其删除
        boolean putSuccesfully = cache.put(key, value);
        if (putSuccesfully) {
            loadingDates.put(key, System.currentTimeMillis());
        }
        return putSuccesfully;
    }

//对MemeryCache的get(String key)做了加强处理:当我们在获取内存Cache中的Bitmap时,如果超过最大存活时间则不返回 @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); } @Override public Bitmap remove(String key) { loadingDates.remove(key); return cache.remove(key); } @Override public Collection<String> keys() { return cache.keys(); } @Override public void clear() { cache.clear(); loadingDates.clear(); } }
复制代码
复制代码
//开源框架默认的内存缓存类,缓存的是bitmap的强引用,
public class LruMemoryCache implements MemoryCache {

    private final LinkedHashMap<String, Bitmap> map;
    //缓存设定的最大值,maxSize 默认的情况下是程序进程占用内存总数的八分之一,单位是Byte。 
    private final int maxSize;
    //** 缓存中已经占有的大小 
    private int size;

    public LruMemoryCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
//true表示排序的顺序是从最远使用到最近使用,而返回false顺序则为插入时的顺序。
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true); } @Override public final Bitmap get(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { return map.get(key); } } /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */ @Override public final boolean put(String key, Bitmap value) { if (key == null || value == null) { throw new NullPointerException("key == null || value == null"); } synchronized (this) { //调用sizeOf这个函数获得该bitmap对象的占用内存的大小,并且让缓存总数增加 size += sizeOf(key, value); //这里就是把对象放入容器中的最核心的一句代码,put()方法如果容器中已经有了此元素,则返回该元素的value值,否则添加进去并返回空 Bitmap previous = map.put(key, value); if (previous != null) { //如果容器中已经有了此元素,则需要把增加的数量减掉 size -= sizeOf(key, previous); } } //此函数计算是否超出最大限量,是则删除队尾元素 trimToSize(maxSize); return true; } //删除最先加入的元素,移除最远使用的Bitmap 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<String, Bitmap> toEvict = map.entrySet().iterator().next(); if (toEvict == null) { break; } key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= sizeOf(key, value); } } } @Override public final Bitmap remove(String key) { if (key == null) { throw new NullPointerException("key == null"); }     //map实例化时并不是线程安全的,所以在所有的操作中都有同步锁。 synchronized (this) {
//存在则返回该Bitmap,不存在返回null Bitmap previous
= map.remove(key); if (previous != null) {
////如果移除的Bitmap存在
size
-= sizeOf(key, previous); } return previous; } } @Override public Collection<String> keys() { synchronized (this) { return new HashSet<String>(map.keySet()); } } @Override public void clear() { trimToSize(-1); // -1 will evict 0-sized elements } private int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override public synchronized final String toString() { return String.format("LruCache[maxSize=%d]", maxSize); } }
复制代码
复制代码
public class FuzzyKeyMemoryCache implements MemoryCache {//对MemoryCache的装饰

    private final MemoryCache cache;
    private final Comparator<String> keyComparator;

    public FuzzyKeyMemoryCache(MemoryCache cache, Comparator<String> keyComparator) {
        this.cache = cache;
        this.keyComparator = keyComparator;
    }

/*对MemoryCache的put(String key, Bitmap value)方法进行加强处理:先移除key相同的Bitmap,再添加新的key对应的Bitmap*/ @Override
public boolean put(String key, Bitmap value) { // Search equal key and remove this entry synchronized (cache) { String keyToRemove = null; for (String cacheKey : cache.keys()) { if (keyComparator.compare(key, cacheKey) == 0) { keyToRemove = cacheKey; break; } } if (keyToRemove != null) { cache.remove(keyToRemove); } } return cache.put(key, value); } @Override public Bitmap get(String key) { return cache.get(key); } @Override public Bitmap remove(String key) { return cache.remove(key); } @Override public void clear() { cache.clear(); } @Override public Collection<String> keys() { return cache.keys(); } }
复制代码

LimitedMemoryCache,WeakMemoryCache

复制代码
//重写LimitedMemoryCache主要是来实现removeNext()方法,以指定超过内存最大限定后移除Bitmap的规则。
public
abstract class LimitedMemoryCache extends BaseMemoryCache { private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16; private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024; private final int sizeLimit;//第2层最大缓存大小16M:多个线程只会读不会写 private final AtomicInteger cacheSize;//当前缓存的大小,原子操作:多个线程会对这个变量进行写 //强引用有引用变量指向时永远不会被垃圾回收。即使内存不足的时候宁愿报OOM也不被垃圾回收器回收,我们new的对象都是强引用 private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>()); /** @param sizeLimit Maximum size for cache (in bytes) */ public LimitedMemoryCache(int sizeLimit) { this.sizeLimit = sizeLimit; cacheSize = new AtomicInteger(); if (sizeLimit > MAX_NORMAL_CACHE_SIZE) { L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB); } } @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) {//如果一个图片大于第2层最大值,则不用进行移除加入第2层了 while (curCacheSize + valueSize > sizeLimit) {//小于最大值加入第二层, Bitmap removedValue = removeNext();//超过第二层最大值时4种移除第2层3层策略,第一层不移除 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; } @Override public Bitmap remove(String key) { Bitmap value = super.get(key);//第1层 if (value != null) {//第1层有 if (hardCache.remove(value)) {//第2层删除 cacheSize.addAndGet(-getSize(value)); } } return super.remove(key);//第1层删除,返回第1层删除的 } @Override public void clear() { hardCache.clear();//第2层删除 cacheSize.set(0); super.clear();//第1层删除 } protected int getSizeLimit() { return sizeLimit; } protected abstract int getSize(Bitmap value); protected abstract Bitmap removeNext(); }
复制代码
复制代码
//这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收掉
public class WeakMemoryCache extends BaseMemoryCache {
    @Override
    protected Reference<Bitmap> createReference(Bitmap value) {
        //弱引用通过weakReference类来实现,如果垃圾回收器扫描到有着WeakReference的对象,就会将其回收释放内存
        return new WeakReference<Bitmap>(value);
    }
}
复制代码

FIFOLimitedMemoryCache,LargestLimitedMemoryCache,LRULimitedMemoryCache,UsingFreqLimitedMemoryCache

复制代码
public class FIFOLimitedMemoryCache extends LimitedMemoryCache {

    private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());

    public FIFOLimitedMemoryCache(int sizeLimit) {
        super(sizeLimit);//设置第2层最大值
    }

    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {//第2层加了,1,3层也要加
            queue.add(value);
            return true;
        } else {//超过第2层总共最大值,第2,3层不添加,只加到第一层
            return false;
        }
    }

    @Override
    public Bitmap remove(String key) {
        Bitmap value = super.get(key);//获取第1层软引用缓存有没有
        if (value != null) {//第1层有
            queue.remove(value);//第3层删除
        }
        return super.remove(key);//第2层
    }

    @Override
    public void clear() {
        queue.clear();//第3层删除
        super.clear();//第2层
    }

    @Override
    protected int getSize(Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    protected Bitmap removeNext() {
        return queue.remove(0);//删除第3层第1个
    }

    @Override
    protected Reference<Bitmap> createReference(Bitmap value) {
        return new WeakReference<Bitmap>(value);
    }
}
复制代码
复制代码
public class LargestLimitedMemoryCache extends LimitedMemoryCache {

    private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

    public LargestLimitedMemoryCache(int sizeLimit) {
        super(sizeLimit);//设置第2层最大值
    }

    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {//第2层加了,1,3层也要加。
            valueSizes.put(value, getSize(value));
            return true;
        } else {//第2层加不进去,3层不加,只加第一层
            return false;
        }
    }

    @Override
    public Bitmap remove(String key) {
        Bitmap value = super.get(key);//第一层
        if (value != null) {//第一层有
            valueSizes.remove(value);//移除第三层
        }
        return super.remove(key);
    }

    @Override
    public void clear() {
        valueSizes.clear();
        super.clear();
    }

    @Override
    protected int getSize(Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    protected Bitmap removeNext() {//删除最大的bitmap对象
        Integer maxSize = null;
        Bitmap largestValue = null;
        Set<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();
        synchronized (valueSizes) {
            for (Entry<Bitmap, Integer> entry : entries) {
                if (largestValue == null) {
                    largestValue = entry.getKey();
                    maxSize = entry.getValue();
                } else {
                    Integer size = entry.getValue();
                    if (size > maxSize) {
                        maxSize = size;
                        largestValue = entry.getKey();
                    }
                }
            }
        }
        valueSizes.remove(largestValue);
        return largestValue;
    }

    @Override
    protected Reference<Bitmap> createReference(Bitmap value) {
        return new WeakReference<Bitmap>(value);
    }
}
复制代码
复制代码
public class LRULimitedMemoryCache extends LimitedMemoryCache {

    private static final int INITIAL_CAPACITY = 10;
    private static final float LOAD_FACTOR = 1.1f;

    private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));

    public LRULimitedMemoryCache(int maxSize) {
        super(maxSize);
    }

    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {
            lruCache.put(key, value);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Bitmap get(String key) {
        lruCache.get(key); // call "get" for LRU logic
        return super.get(key);
    }

    @Override
    public Bitmap remove(String key) {
        lruCache.remove(key);
        return super.remove(key);
    }

    @Override
    public void clear() {
        lruCache.clear();
        super.clear();
    }

    @Override
    protected int getSize(Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    protected Bitmap removeNext() {
        Bitmap mostLongUsedValue = null;
        synchronized (lruCache) {
            Iterator<Entry<String, Bitmap>> it = lruCache.entrySet().iterator();
            if (it.hasNext()) {
                Entry<String, Bitmap> entry = it.next();
                mostLongUsedValue = entry.getValue();
                it.remove();
            }
        }
        return mostLongUsedValue;
    }

    @Override
    protected Reference<Bitmap> createReference(Bitmap value) {
        return new WeakReference<Bitmap>(value);
    }
}
复制代码
复制代码
public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {

    private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

    public UsingFreqLimitedMemoryCache(int sizeLimit) {
        super(sizeLimit);
    }

    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {
            usingCounts.put(value, 0);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Bitmap get(String key) {//读取一次加1
        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
    public Bitmap remove(String key) {
        Bitmap value = super.get(key);
        if (value != null) {
            usingCounts.remove(value);
        }
        return super.remove(key);
    }

    @Override
    public void clear() {
        usingCounts.clear();
        super.clear();
    }

    @Override
    protected int getSize(Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    protected Bitmap removeNext() {
        Integer minUsageCount = null;
        Bitmap leastUsedValue = null;
        Set<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();
        synchronized (usingCounts) {
            for (Entry<Bitmap, Integer> 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;
    }

    @Override
    protected Reference<Bitmap> createReference(Bitmap value) {
        return new WeakReference<Bitmap>(value);
    }
}
复制代码

 



本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/6351216.html,如需转载请自行联系原作者

相关文章
|
6月前
|
安全 虚拟化
在数字化时代,网络项目的重要性日益凸显。本文从前期准备、方案内容和注意事项三个方面,详细解析了如何撰写一个优质高效的网络项目实施方案,帮助企业和用户实现更好的体验和竞争力
在数字化时代,网络项目的重要性日益凸显。本文从前期准备、方案内容和注意事项三个方面,详细解析了如何撰写一个优质高效的网络项目实施方案,帮助企业和用户实现更好的体验和竞争力。通过具体案例,展示了方案的制定和实施过程,强调了目标明确、技术先进、计划周密、风险可控和预算合理的重要性。
115 5
|
4月前
|
监控 安全 数据可视化
哪些项目适合采用BOT+EPC模式?深度解析
2分钟了解什么是BOT+EPC项目管理模式以及该模式适用于哪些类型的项目。
208 1
哪些项目适合采用BOT+EPC模式?深度解析
|
6月前
|
存储 缓存 安全
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
98 6
|
1月前
|
缓存 NoSQL Go
【LeetCode 热题100】146:LRU 缓存(详细解析)(Go语言版)
本文详细解析了力扣 146 题——LRU 缓存机制的实现方法。通过结合哈希表与双向链表,确保 `get` 和 `put` 操作均在 O(1) 时间内完成。哈希表用于快速查找,双向链表记录访问顺序,支持最近使用数据的高效更新与淘汰。代码以 Go 语言实现,结构清晰,涵盖核心操作如节点移动、插入与删除。此题为面试高频考点,适用于数据缓存、页面置换等场景,掌握后可加深对缓存策略的理解。
70 4
|
2月前
|
机器学习/深度学习 人工智能 缓存
MHA2MLA:0.3%数据微调!复旦团队开源推理加速神器,KV缓存狂降96.87%
MHA2MLA是复旦大学、华东师范大学、上海AI Lab等机构联合推出的数据高效微调方法,通过引入多头潜在注意力机制(MLA),显著优化基于Transformer的LLM推理效率,降低推理成本。
107 1
MHA2MLA:0.3%数据微调!复旦团队开源推理加速神器,KV缓存狂降96.87%
|
3月前
|
机器学习/深度学习 存储 缓存
LLM高效推理:KV缓存与分页注意力机制深度解析
随着大型语言模型(LLM)规模和复杂性的增长,高效推理变得至关重要。KV缓存和分页注意力是优化LLM推理的两项关键技术。KV缓存通过存储键值对减少重复计算,而分页注意力则通过将序列分割成小块来降低内存消耗,从而有效处理长序列。本文深入剖析这些技术的工作原理及其在仅解码器模型中的应用,探讨其优势与挑战,并展示其实现示例。
137 16
LLM高效推理:KV缓存与分页注意力机制深度解析
|
4月前
|
数据可视化 项目管理
项目计划与进度跟踪:甘特图的强大功能解析
甘特图是现代项目管理中不可或缺的工具,通过时间线和任务条直观展示项目进度,支持任务分解、依赖关系管理和进度跟踪。结合板栗看板,可实现任务可视化与实时协作,提升团队效率。定期更新甘特图并灵活应对变化,确保项目顺利推进。
|
4月前
|
消息中间件 Linux
Linux:进程间通信(共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)
通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。
312 20
|
4月前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
134 6
|
6月前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####

推荐镜像

更多