Glide中的LruBitmapPool剖析

LruBitmapPool

LruBitmapPool為何而生呢?

摘抄自網(wǎng)上的一段解釋:
alvik和ART都沒有使用compacting garbage collector垃圾回收模式,這種模式中GC會遍歷堆,同時把活躍對象移到相鄰內(nèi)存區(qū)域,讓更大的內(nèi)存塊可以用在后續(xù)的分配中。因為安卓沒有這種模式,就可能會出現(xiàn)被分配的對象分散在各處,對象之間只有很小的內(nèi)存可用。如果應用試圖分配一個大于鄰近的閑置內(nèi)存塊空間的對象,就會導致OOM崩潰,即使總的空余內(nèi)存空間大于要分配的對象的大小。
而且,同步GC時會暫停所有線程(包括UI主線程)以便進行GC,雖然暫停時間很短,但頻繁的同步GC會造成頁面卡頓,從而影響用戶體驗。
因此為了避免頻繁的創(chuàng)建以及回收Bitmap對象,進而減少GC的出現(xiàn),可以使用BitmapPool統(tǒng)一的管理Bitmap的創(chuàng)建以及重用。

使用LruBitmapPool后解決了些什么問題呢?

因為Glide提供了LruBitmapPool方法,從而使用圖片的加載進一步高效化,從上面的解釋,簡單概括就是避免Bitmap的頻繁創(chuàng)建,提高復用,減少了內(nèi)存抖動

內(nèi)存抖動是由于短時間內(nèi)有大量對象進出Young Generiation區(qū)導致的,它伴隨著頻繁的GC。

LruBitmapPool源碼剖析

lrubitmappool.jpeg

從圖中大致可以了解到其LruBitmapPool調(diào)用流程(注意如果使用into(target)方法則不會使用LruBitmapPool機制),在位圖轉(zhuǎn)換的時候去查找LruBitmapPool中是否存在大小和配置信息相同的bitmap,有則返回

主要方法

put方法

@Override
  public synchronized void put(Bitmap bitmap) {
    if (bitmap == null) {
      throw new NullPointerException("Bitmap must not be null");
    }
    if (bitmap.isRecycled()) {
      throw new IllegalStateException("Cannot pool recycled bitmap");
    }
    if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize
        || !allowedConfigs.contains(bitmap.getConfig())) {
      bitmap.recycle();
      return;
    }
    final int size = strategy.getSize(bitmap);
    strategy.put(bitmap);//存入LruPoolStrategy中
    tracker.add(bitmap);
    puts++;
    currentSize += size;
    dump();//輸出log信息
    evict();//根據(jù)currentSize計算是否超出maxSize,是則進行末位回收
  }

get方法

傳入大小及配置信息來查找相匹配的位圖

  @Override
  @NonNull
  public Bitmap get(int width, int height, Bitmap.Config config) {
    Bitmap result = getDirtyOrNull(width, height, config);
    if (result != null) {
      result.eraseColor(Color.TRANSPARENT);//如果對象池存在位圖則擦拭該位圖像素
    } else {
      result = Bitmap.createBitmap(width, height, config);//創(chuàng)新新的位圖
    }
    return result;
  }

getDirtyOrNull方法

  @Nullable
  private synchronized Bitmap getDirtyOrNull(int width, int height, Bitmap.Config config) {
    assertNotHardwareConfig(config);
    final Bitmap result = strategy.get(width, height, config != null ? config : DEFAULT_CONFIG);
    if (result == null) {
      misses++;
    } else {
      hits++;
      currentSize -= strategy.getSize(result);
      tracker.remove(result);
      normalize(result);
    }
    dump();
    return result;
  }

在調(diào)用LruBitmapPool.get方法獲取到Bitmap后,通過如下方法將獲取到的bitmap作為參數(shù)傳給Canvas,在canvas中把inBitmap像素填充到進去,通過對象復用,很好的優(yōu)化了內(nèi)存抖動問題


  private static void applyMatrix(@NonNull Bitmap inBitmap, @NonNull Bitmap targetBitmap,
      Matrix matrix) {
    BITMAP_DRAWABLE_LOCK.lock();
    try {
      Canvas canvas = new Canvas(targetBitmap);
      canvas.drawBitmap(inBitmap, matrix, DEFAULT_PAINT);
      clear(canvas);
    } finally {
      BITMAP_DRAWABLE_LOCK.unlock();
    }
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容