sky’s 雑記

主にAndroidとサーバーサイドの技術について記事を書きます

Glide4系のDiskCacheStrategyについて

全然更新してないけどandroidネタ。 記事執筆時点でのglideレポジトリの最新masterです。

ギガを食うのを改善したいとの要望がありGlideのDiskCacheを調査したときのログ

TL;DL

  • /data/data/app_dir/image_manager_disk_cacheに保存される
  • キャッシュアルゴリズムはLRU(Least Recently Used)
  • キャッシュ容量はデフォルトで250MB(25010241024)

キャッシュの保存場所や容量について

デフォルトはinternalなimage_manager_disc_cacheディレクトリに容量250MBまで保存可

これらはGlideModuleを定義すれば変更可

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
  }
}

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));
  }
}

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
    builder.setDiskCache(
        new InternalCacheDiskCacheFactory(context, "cacheFolderName", diskCacheSizeBytes));
  }
}

refs

https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/load/engine/cache/DiskCache.java

キャッシュ戦略とアルゴリズムについて

デフォルトではAUTOMATIC

リモートデータは特に処理を加えずそのままキャッシュする。ローカルデータは必要があればリサイズ等の処理を加えた上でキャッシュする。

実装

image_manager_disc_cacheには .0 拡張子ファイルと jornal が存在する。 jornalの中身は以下のような構成

libcore.io.DiskLruCache
1
100
2

CLEAN  832 21054
DIRTY 335c4c6028171cfddfbaae1a9c313c52
CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
REMOVE 335c4c6028171cfddfbaae1a9c313c52
DIRTY 1ab96a171faeeee38496d8b330771a7a
CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
READ 335c4c6028171cfddfbaae1a9c313c52
READ 3400330d1dfc7f3f7f4b8d4d803dfcf6

3400330d1dfc7f3f7f4b8d4d803dfcf6 → 画像urlから生成されるハッシュ値 3934 2342メタデータと実レスポンスサイズ

DIRTY → キャッシュ中 CLEAN → キャッシュ済み READ → アプリによりアクセス中 REMOVE → 削除対象

これらステータスを逐一読み取りキャッシュ管理を行う

アルゴリズム

LRU(Least Recently Used) 上記実装で更新が走ったものが後列に積まれる

ジャーナルのリビルド

キャッシュサイズが上限に達する or redundantOpCount(REMOVE) が2000以上かつサイズがhalveになっている場合にjournalのリビルド及びcacheの削除を行う(とコメントにあったが実装と食い違っているような気がするので詳しい人教えてください。)

 /**
   * We only rebuild the journal when it will halve the size of the journal
   * and eliminate at least 2000 ops.
   */
  private boolean journalRebuildRequired() {
    final int redundantOpCompactThreshold = 2000;
    return redundantOpCount >= redundantOpCompactThreshold //
        && redundantOpCount >= lruEntries.size();
  }
 private void trimToSize() throws IOException {
    while (size > maxSize) {
      Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
      remove(toEvict.getKey());
    }
  }

 /** This cache uses a single background thread to evict entries. */
  final ThreadPoolExecutor executorService =
      new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
          new DiskLruCacheThreadFactory());
  private final Callable<Void> cleanupCallable = new Callable<Void>() {
    public Void call() throws Exception {
      synchronized (DiskLruCache.this) {
        if (journalWriter == null) {
          return null; // Closed.
        }
        trimToSize();
        if (journalRebuildRequired()) {
          rebuildJournal();
          redundantOpCount = 0;
        }
      }
      return null;
    }
  };

refs

https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/load/engine/DiskCacheStrategy.java https://futurestud.io/tutorials/retrofit-2-analyze-cache-files

apendix

主要なクラスの関係は以下の通り DiskLruCache.java | DiskLruCacheWrapper.java | DiskLruCacheFactory.java | InternalCacheDiskCacheFactory / InternalCacheDiskCacheFactory | GlideBuilder