google-guava の MapMaker の使用に問題があります。コードは次のとおりです。
package test;
import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.Random;
import com.google.common.collect.MapEvictionListener;
import com.google.common.collect.MapMaker;
public class MapMakerTest {
private static Random RANDOM = new Random();
private static char[] CHARS =
("abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"1234567890-=!@#$%^&*()_+").toCharArray();
public static void main(String[] args) throws Exception {
MapEvictionListener<String, String> listener = new MapEvictionListener<String, String>() {
@Override
public void onEviction(String key, String value) {
System.out.println(">>>>> evicted");
}
};
Map<String, String> map = new MapMaker().
concurrencyLevel(1).softValues().
evictionListener(listener).makeMap();
while (true) {
System.out.println(map.size());
String s = getRandomString();
map.put(s, s);
Thread.sleep(50);
}
}
private static String getRandomString() {
int total = 50000;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < total; ++i) {
sb.append(CHARS[RANDOM.nextInt(CHARS.length)]);
}
return sb.toString();
}
}
Java が次のように呼び出されるとjava -Xms2m -Xmx2m -cp guava-r09.jar:. test.MapMakerTest(ヒープ設定は、何が起こるかを簡単に確認できるように意図的に非常に小さくなっています)、60 回目の反復のあたりで、OutOfMemoryError: HeapSpace で爆発します。
ただし、マップがMap<String, SoftReference<String>>(そして、コードの残りの部分 (リスナーと put) の変更に応じて変更されている場合) は、エビクションが行われていることがわかり、コードは単純に機能し、値はガベージ コレクションされます。
http://guava-libraries.googlecode.com/svn/tags/release09/javadoc/index.htmlを含むすべてのドキュメントで、SoftReferences について明示的に言及されていません。put が呼び出されたときに Map 実装が SoftReference の値をラップすることになっていませんか? 私は想定される使用法について本当に混乱しています。
私はグアバr09を使用しています。
誰かが私が間違っていること、そしてなぜ私の仮定が間違っているのか説明できますか?
よろしく、 ウージェク