Glide内存缓存

99 阅读2分钟

Glide内存缓存: 首先你要知道什么时候用到了内存缓存:答案是在:engine.load的时候:当从内存缓存里面找到了可以使用的engineSource时候,就会把当前的engineSource添加到活动缓存里面。
其实内存缓存分为两个:活动缓存activityReources和内存缓存LruResourceCache。他们两个缓存的数据不会重复。当系统发生gc的时候,所有的数据会从activityResources里面移除放进LreResourceCache里面。然后当从LruResourceCache里面查到数据的时候会从LruResourceCache里面移除然后添加到activityResources里面。

class Engine{
    private EngineResource<?> loadFromMemory(
        EngineKey key, boolean isMemoryCacheable, long startTime) {
      if (!isMemoryCacheable) {
        return null;
      }
      // 看活动缓存能拿到东西不
      EngineResource<?> active = loadFromActiveResources(key);
      if (active != null) {
        return active;
      }
      //看内存缓存能拿到数据不
      EngineResource<?> cached = loadFromCache(key);
      if (cached != null) {
        return cached;
      }
      return null;
    }
    
    // 可以看到如果在内存缓存里面找到了engineSource,那么就把engineSource添加到活动缓存里面。
    private EngineResource<?> loadFromCache(Key key) {
      EngineResource<?> cached = getEngineResourceFromCache(key);
      if (cached != null) {
        cached.acquire();
        activeResources.activate(key, cached);
      }
      return cached;
    }

    private EngineResource<?> getEngineResourceFromCache(Key key) {
    // 找到了就会从内存缓存里面进行移除
      Resource<?> cached = cache.remove(key);

      final EngineResource<?> result;
      if (cached == null) {
        result = null;
      } else if (cached instanceof EngineResource) {
        result = (EngineResource<?>) cached;
      } else {
        result =
            new EngineResource<>(
                cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
      }
      return result;
    }
}

内存缓存也就是LruResourceCache,需要我们进行深度学习一下:LruResourceCahce里面用到了LinkedHashMap。为什么不用hashMap呢。因为hashMap是无序的,在Glide的内存缓存里面,需要在数据达到限制的时候去删除最近最少使用的数据,那我们既然要知道数据是不是最近最少使用的话,就要使用到Linkedhashmap的特性。他通过牺牲空间和时间维护了一个双向链表来保证迭代顺序。

来看下LruResourceCached的put操作:

// LruCache.java
public synchronized Y put(@NonNull T key, @Nullable Y item) {
  final int itemSize = getSize(item);
  if (itemSize >= maxSize) {
    onItemEvicted(key, item);
    return null;
  }

  if (item != null) {
    currentSize += itemSize;
  }
  @Nullable Entry<Y> old = cache.put(key, item == null ? null : new Entry<>(item, itemSize));
  if (old != null) {
    currentSize -= old.size;
    if (!old.value.equals(item)) {
      onItemEvicted(key, old.value);
    }
  }
  evict();

  return old != null ? old.value : null;
}
private void evict() {
  trimToSize(maxSize);
}
// 超过缓存限制的时候删除最近最少使用的节点。
protected synchronized void trimToSize(long size) {
  Map.Entry<T, Entry<Y>> last;
  Iterator<Map.Entry<T, Entry<Y>>> cacheIterator;
  while (currentSize > size) {
    cacheIterator = cache.entrySet().iterator();
    last = cacheIterator.next();
    final Entry<Y> toRemove = last.getValue();
    currentSize -= toRemove.size;
    final T key = last.getKey();
    cacheIterator.remove();
    onItemEvicted(key, toRemove.value);
  }
}
  1. 过大的图片不被允许进行缓存。
  2. 每一个EngineResource会被包装在Entry里面

总结: 活动缓存他是通过弱引用的方式将EngeineResource保存在了HashMap里面。这个容量是没有限制的。然后从活动缓存里面移除的数据会被保存在内存缓存也就是LruCachedResource里面。这个里面可以动态设置一个maxSize值用来限制他的大小,当超过这个值的时候他是采用删除最近最少使用的方式来维持缓存大小。