Glide看点(三) 内存管理

栏目: IOS · Android · 发布时间: 6年前

内容简介:Glide里的缓存是一个精妙的多级缓存,从文档里我们可以知道总的缓存策略如下:本文讲分析Glide对于Bitmap的内存缓存逻辑:Glide里有内存里分别有两层缓存,一个是Active Cache一个是普通的Cache。他们本质上都是LinkedHashMap实现的LRUCache,只是调度策略让他们拥有了不同的功能。

Glide看点(三) 内存管理

Glide里的缓存是一个精妙的多级缓存,从文档里我们可以知道总的缓存策略如下:

默认情况下,Glide 会在开始一个新的图片请求之前检查以下多级的缓存:

活动资源 (Active Resources) – 现在是否有另一个 View 正在展示这张图片?

内存缓存 (Memory cache) – 该图片是否最近被加载过并仍存在于内存中?

资源类型(Resource) – 该图片是否之前曾被解码、转换并写入过磁盘缓存?

数据来源 (Data) – 构建这个图片的资源是否之前曾被写入过文件缓存?

前两步检查图片是否在内存中,如果是则直接返回图片。后两步则检查图片是否在磁盘上,以便快速但异步地返回图片。

如果四个步骤都未能找到图片,则Glide会返回到原始资源以取回数据(原始文件,Uri, Url等)。

本文讲分析Glide对于Bitmap的内存缓存逻辑:

ActiveCache的使用

Glide里有内存里分别有两层缓存,一个是Active Cache一个是普通的Cache。他们本质上都是LinkedHashMap实现的LRUCache,只是调度策略让他们拥有了不同的功能。

从load方法来看策略:

EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      return null;
    }

    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      return null;
    }
  • 加载时先从Active Cache里检查,如果没有再从普通的Cache里拿去
  • 当从Normal cache里取出来后会把对象加入到Activie里,并且从普通的cache里移除
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    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) {
      // Save an object allocation if we've cached an EngineResource (the typical case).
      result = (EngineResource<?>) cached;
    } else {
      result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/);
    }
    return result;
  }
  • 当resource release的时候会在active resouce移除对象,在普通cache里加入
@Override
  public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
    Util.assertMainThread();
    activeResources.deactivate(cacheKey);
    if (resource.isCacheable()) {
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource);
    }
  }

画个数据流图看得更直观一些

Glide看点(三) 内存管理

注: resource release时机解释:每个资源有一个自己的使用计数,每当使用的时候会调用acquire方法给计数加1,每次job完成后会计数减1,当计数为零时进行release

Object Pool的使用

我们知道如果较短时间内频繁的新建对象是会造成内存的抖动,可能造成界面的卡顿。

Glide看点(三) 内存管理

Object Pool就是为了避免这种情况发生的一种常见设计模式。它会初始化一些列的对象,当需要对象的时候不是去创建一个新的对象,二手去复用闲置的对象资源。当没有闲置资源的时候进行扩容。

Glide里大量使用了Object Pool的实现。

Bitmap Pool

Bitmap Pool是保证Bitmap回收使用管理的类,避免了Bitmap被大量创建造成频繁GC的问题。

下面已LRUBitmapPool为安利分析

LRUBitmapPool持有LruPoolStrategy(具体实现是SizeStrategy,SizeConfigStrategy),它是正常持有Bitmap缓存的地方

com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool


  private final KeyPool keyPool = new KeyPool();

  private final GroupedLinkedMap<Key, Bitmap> groupedMap = new GroupedLinkedMap<>();

  private final NavigableMap<Integer, Integer> sortedSizes = new PrettyPrintTreeMap<>();

Key 根据width和height算出实际的bitmap大小的一个类,作为HashMap的键 (后面会解释为什么Key是bitmap大小)

KeyPool是用宽高生成一个Key的ObjectPool

groupedMap: 缓存Bitmap的对象,是一个修改过的LinkedHashMap作为LRU cache

sortedSizes: 记录每个Key下对应的Bitmap的数量,且已大小排序

为什么Bitmap Pool的Key是Bitmap的尺寸

Android里默认的API每次decode bitmap或则一些对bitmap的操作时默认是新创建一张Bitmap。API 11以后提供了BitmapFactory.Options.inBitmap这个变量来告诉系统去复用原来的已经存在的bitmap而不是重新创建bitmap从而达到节省内存的目的。

但是inBitmap的使用有一些限制,复用的bitmap的大小必须大于等于原来的尺寸。所以需要用bitmap的尺寸作为Key来缓存bitmap。

Glide看点(三) 内存管理

其他Tips

  • 不同的BitMapConfig不能复用,所以需要用不同的Pool来缓存bitmap。这里也就是Glide里的

    com/bumptech/glide/load/engine/bitmap_recycle/SizeConfigStrategy.java 存在的意义

    Glide看点(三) 内存管理

总结

  • 从Glide里我们可以学习到如何用LruCache建立多级缓存的逻辑。
  • 如何使用inBitmap对bitmap进行缓存
  • LinkedHashMap是如何实现LRU管理的(双向循环链表)
    ## 参考
    Glide v4 Caching
    Re-using Bitmaps

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Development with Rails, Third Edition

Agile Web Development with Rails, Third Edition

Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2009-03-17 / USD 43.95

Rails just keeps on changing. Rails 2, released in 2008, brings hundreds of improvements, including new support for RESTful applications, new generator options, and so on. And, as importantly, we’ve a......一起来看看 《Agile Web Development with Rails, Third Edition》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具