MapMaker を使用して、大きなオブジェクトをキャッシュするマップを作成したいと考えています。これは、十分なメモリがない場合はキャッシュから削除する必要があります。この小さなデモ プログラムは問題なく動作するようです。
public class TestValue {
private final int id;
private final int[] data = new int[100000];
public TestValue(int id) {
this.id = id;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalized");
}
}
public class Main {
private ConcurrentMap<Integer, TestValue> cache;
MemoryMXBean memoryBean;
public Main() {
cache = new MapMaker()
.weakKeys()
.softValues()
.makeMap();
memoryBean = ManagementFactory.getMemoryMXBean();
}
public void test() {
int i = 0;
while (true) {
System.out.println("Etntries: " + cache.size() + " heap: "
+ memoryBean.getHeapMemoryUsage() + " non-heap: "
+ memoryBean.getNonHeapMemoryUsage());
for (int j = 0; j < 10; j++) {
i++;
TestValue t = new TestValue(i);
cache.put(i, t);
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main m = new Main();
m.test();
}
}
ただし、実際のアプリケーションで同じことを行うと、エントリは基本的に追加されるとすぐにキャッシュから削除されます。私の実際のアプリケーションでは、整数もキーとして使用します。キャッシュされた値は、データを含むディスクから読み取られたアーカイブ ブロックです。私が理解している限り、弱参照は使用されなくなるとすぐにガベージコレクションされるため、キーが弱参照であるため、これは理にかなっているようです。次のようにマップを作成すると:
data = new MapMaker()
.softValues()
.makeMap();
エントリがガベージ コレクションされることはなく、テスト プログラムでメモリ不足エラーが発生します。TestValue エントリの finalize メソッドは呼び出されません。テスト方法を次のように変更すると:
public void test() {
int i = 0;
while (true) {
for (final Entry<Integer, TestValue> entry :
data.entrySet()) {
if (entry.getValue() == null) {
data.remove(entry.getKey());
}
}
System.out.println("Etntries: " + data.size() + " heap: "
+ memoryBean.getHeapMemoryUsage() + " non-heap: "
+ memoryBean.getNonHeapMemoryUsage());
for (int j = 0; j < 10; j++) {
i++;
TestValue t = new TestValue(i);
data.put(i, t);
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
}
エントリがキャッシュから削除され、TestValue オブジェクトのファイナライザーが呼び出されますが、しばらくするとメモリ不足エラーも発生します。
私の質問は、MapMaker を使用してキャッシュとして使用できるマップを作成する正しい方法は何ですか? weakKeys を使用すると、テスト プログラムができるだけ早くエントリを削除しないのはなぜですか? キャッシュ マップに参照キューを追加することはできますか?