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
キャッシュ戦略とアルゴリズムについて
デフォルトでは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