2017-07-13 7 views
8

LRUCacheについての公式のAndroidドキュメントをチェックアウトしました。値にアクセスするたびに、キューの先頭に移動されます。値がフル・キャッシュに追加されると、そのキューの最後の値は追い出され、ガベージ・コレクションの対象となる可能性があります。 これはキャッシュによって使用されるlinkedhashmapによって維持される二重リンクリストであるとします。この動作を確認するには、LruCacheのソースコードをチェックアウトし、get(Kキー)メソッドをチェックしました。さらに、マップのgetメソッドを呼び出して、基になるハッシュマップから値を取得し、recordAccessメソッドを呼び出します。順番にgetを使用したときのLRUCacheエントリの並べ替え

public V get(Object key) { 
    LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key); 
    if (e == null) 
     return null; 
    e.recordAccess(this); 
    return e.value; 
} 

recordAccess方法がaccessOrderがtrueに設定されている場合には、リストの最後にアクセスされたエントリを移動し、他のことは何もしない、(私の問題のためのそれであると仮定しましょう)。

/** 
    * This method is invoked by the superclass whenever the value 
    * of a pre-existing entry is read by Map.get or modified by Map.set. 
    * If the enclosing Map is access-ordered, it moves the entry 
    * to the end of the list; otherwise, it does nothing. 
    */ 
    void recordAccess(HashMap<K,V> m) { 
     LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; 
     if (lm.accessOrder) { 
      lm.modCount++; 
      remove(); 
      addBefore(lm.header); 
     } 
    } 

これは、要素がキューの先頭に移動したという上記のステートメントと矛盾しています。代わりに、リストの最後の要素に移動します(head.beforeを使用)。確かに、私はここに何かを逃しています、どんな助け? LinkedHashMapのjavadocツールから

+0

私はあなたがチェックしているソースする何見当がつかない、私は唯一の[この](https://android.googlesource.com/platform/frameworks/support.git/+/795b97d901e1793dac5c3e67d43c96a758fec388/v4/java/android/support見ることができます/v4/util/LruCache.java#63) – pskink

+0

同じソースをチェックしていますが、実際の並べ替えはLinkedHashMapクラスで行われます(これはリストが維持されるためです)。map.get ) 方法。 –

+1

OK、 '' LinkedHashMap'の実装の詳細ではなく、いくつかの仮想 ''キュー ''を参照します(マッピングは逆になります) – pskink

答えて

2

LinkedHashMapについては、LruCacheのドキュメントを読んでいるだけです。 LinkedHashMapには、特にaccessOrderに関する独自のドキュメントがあります。 (Java docsに同じ)。

[... accessOrder =真...]反復の順序から最小最近最も最近(アクセス順)にアクセスし、そのエントリが最後にアクセスされた順序、ある

したがって、LinkedHashMapは、最後に使用されたエントリを最後に置き、文書化されています。

実際LruCache、このようなキャッシュは理論的には動作しますが、LinkedHashMapは別々の後方移動イテレータを追加することなく、それを実装する方法を示しています方法について説明します。最後に、最近の要素を置くことによって、trimmingはすでに利用可能な(前方移動)イテレータを使用することができます古い要素に効率的にアクセス(および削除)します。

ここで私は何が間違っていたのかをremoveEldestEntryで知ることはできませんでしたが、おそらく過去に存在しなかったでしょう。

1

3つの引数のコンストラクタを使用する場合、および accessOrder として指定され、反復は、エントリがアクセスされた順になります。アクセス順序は、となります。,putAll操作の影響を受けますが、コレクションビューの操作では影響を受けません。

Exactly the case、そのLruCacheが有する。

public LruCache(int maxSize) { 
    if (maxSize <= 0) { 
     throw new IllegalArgumentException("maxSize <= 0"); 
    } 
    this.maxSize = maxSize; 
    this.map = new LinkedHashMap<K, V>(0, 0.75f, true); 
} 

のはrecordAccess()が何をするか見てみましょう:

void recordAccess(HashMap<K,V> m) { 
     LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; 
     if (lm.accessOrder) { // true, because `LruCache` instantiated this 
           // map with `accessOrder = true` 
      lm.modCount++; 
      remove(); // remove this `LinkedHashMapEntry` from the map 
      addBefore(lm.header); // adds this entry before the current header of 
            // the map, thus this entry becomes the header 
     } 
    } 

は、その代わりに、(head.beforeを使用して)リストの最後の要素に移動します。

あなたの声明がどのように有効であるかわかりません。

+0

ヘッダーになるエントリは、addBeforeメソッドでlm.headerを変更する必要があります。 lm.headerフィールドにはヘッダが変更されるような割り当てはありません。 –

+0

[addBefore()実装](https://android.googlesource.com/platform/libcore/+/0976dc2/ojluni/src/main/java/java/util/LinkedHashMap.java#356)では、入力項目は現在のヘッダ項目の「前」項目として追加され、入力項目の「後」項目は前の項目に追加されます。だから、ちょうど参考文献が投げ回されている。 – azizbekian

+0

は、項目がheader.beforeとして追加され、ポインタがヘッダをポイントした後であることに同意しました。しかし、ヘッダー自体は更新されません。ヘッダーの前に何かを追加する方法です。しかし、私はlm.header(メソッドに渡された)のフィールドが変更されていないことを知りません。これは私の問題の基礎を形成します。 –

関連する問題