2017-01-03 9 views
0

私は、DoublyLinkedListの独自の実装を使用してJavaでLRUキャッシュを実装していますが、整数のキーと値を持つノードでキーがページ識別子を示し、ディスク。また、O(1)アクセス用のハッシュマップを使用しています。LRUキャッシュのJavaインプリメンテーションでミスが発生した場合のSETアクション

要求されたキーがキャッシュヒットの場合、その値(つまり、その位置)を返し、このノードをDoublyLinkedListの前面に移動します。

私はそれが欠場しているときには、他の重要な側面に疑念があります。さまざまなリソースによれば、私の場合はキーであるページ番号がLinkedListの先頭にセットされ、その間に満杯になると、最後に要素を削除してからそれを正面に入力してください。今実装するために、キャッシュにそのページ番号(キー)を入れるとき、そのページ番号(キー)の「価値」はどうなのでしょうか?私はそれをゴミにセットすべきですか?私の下で提示された 'get'メソッドの実装では、私は現在-1を返しています。

また、実際のLRUキャッシュの製造コードでは、キャッシュにページ番号または実際の値が格納されていますか? T

この部分をクリアしてください。ありがとう。

import java.util.HashMap; 


public class LRU { 

private static class Node { 

    Node previous; 
    Node next; 
    int key; 
    int value; 

    public Node(int key, int value) { 
     this.key = key; 
     this.value = value; 
    } 
} 

Node head = null; 
Node tail = null; 

HashMap<Integer, Node> hmap = new HashMap<>(); 

public int get(int key) { 
    if (hmap.containsKey(key)) { 
     Node n = hmap.get(key); 
     remove(n); 
     moveToFront(n); 
     return n.value; 
    } 
    return -1; 
} 

public void remove(Node n) { 
    // if n is head 
    if (n.previous == null) { 
     head = head.next; 
    } else { 
     n.previous.next = n.next; 
    } 

    //if n is tail 
    if (n.next == null) { 
     tail = n.previous; 
    } else { 
     n.next.previous = n.previous; 

    } 
} 

public void moveToFront(Node n) { 
    if(n==head) 
     return; 
    if(n.next==null) 
    { 
     n.previous.next=n.next; 
     tail = n.previous;      
     n.previous = null; 
     n.next = head; 
     head = n; 
    } 
    else { 
     n.previous.next=n.next; 
     n.next.previous=n.previous; 
    } 
} 

public void set(int key, int value) { 

    } 
} 
+0

"実用的なプロダクションコード"では、独自のコードを展開する代わりに、 'LinkedHashMap'を使用します。それ以外に、存在しないエントリを表すノードを挿入することは意味を成さない。この時点で、「ページ番号」または「ページ番号に格納された実際の値」が何を意味するのかを明示せずに、一種のマップを記述しただけです。だからこそ質問はしないでください。このデータにはキャッシュが必要だと決めたのはあなたです。 – Holger

+0

簡単に行ってください。ここルーキー。 –

+0

あなたが説明しなかったあなたのアプリケーションに特有の事柄については、私たちが質問に答えることができないことを理解するために、「ルーキー」とは何の関係もありません。 LRUキャッシュの作成は、[このコンストラクタ](https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html#LinkedHashMap-int-float)を使用して、 'LinkedHashMap'をサブクラス化するのと同じくらい簡単です。 -boolean-)を 'true'で置き換えると、ヒットするとエントリが前面に移動し、[' removeEldestEntry']を上書きします(https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html# removeEldestEntry-java.util.Map.Entry-)、ドキュメントには既に固定サイズの処理方法が示されています。 – Holger

答えて

0

キャッシュという用語は、一般に、容量が制限されたキーと値のペアマップを識別します。容量に達したときに新しいペアを追加しようとすると、既存のキーと値のペアの1つが追い出され、新しいものが追加されます。通常、ペアの追加は、キャッシュに現在格納されていないキーの値を取得しようとする(つまり、キャッシュが追い出しを実行し、新しいペアをロードして値を返す)ための関数として暗黙的に発生します。

LRU(Least Recently Used)は、排除されるペアを選択するためのポリシーの1つで、唯一のものではありません。プロセッサデータキャッシュは、ハードウェアに実装されたキャッシュの一例であり、キーはアドレス(通常は特定の数の最上位ビットのみを考慮する)から得られ、その値はそのようなアドレスを含むメモリの一部であるキャッシュラインには、メモリに存在するデータのコピーが含まれています。 もう1つの例は、仮想メモリをサポートするOSで、OSカーネル内にHW(MMU)とソフトウェアの組み合わせとして実装されたOSページングです。この例では、説明に近いものの、ペアの値は、仮想ページをホストするメモリページの物理アドレスです。

「LRUキャッシュの実用的な生産コードでは、キャッシュにページ番号または実際の値が格納されていますか?」という質問に対しては、私たちが話しているキャッシュ。あなたの場合、キャッシュが裏付けされているものは明確ではありません。私はそれがいくつかのファイルのオフセットだと仮定します。その場合、私はあなたの値がバイト配列またはファイルの一部を表す文字列であることを期待します。ファイル内のオフセットxへのアクセスは、key = offset/PAGE_SIZEにマップされます。キーがテーブルに存在せず、テーブルの容量がある場合は、最後のノードを「リサイクル」することができます。既存のキーの置き換え、オフセット時のファイルの内容の読み取り(key、key + PAGE_SIZE-1 )をバイトバッファに格納し、最後にページを最初に移動します。

+0

これは素晴らしかったです!最後の行について:「バイトバッファのオフセット(キー、キー+ PAGE_SIZE-1)でファイルの内容を読む」 - オフセット(key + PAGE_SIZE-1)は何を意味していますか?メモリがバイトアドレスの場合、そのアドレスでシングルバイトだけを読み取らないでしょうか? –

+0

8Kbのページがあるとします。ユーザはオフセット9000でバイトを読むことを要求する。ページインデックスは9000/8192 = 1である。キャッシュ置換コードはページ1全体、すなわち範囲(8192,8192 + 8191)を持ち込むべきである。このコードは、オフセット9000%8192 = 808でそのページ内のバイトを返します。 –

+0

今や意味があります。どうもありがとう! –

関連する問題