google-guava MapMaker .softValues () - значения не получают GC-ed, OOME: HeapSpace следует
У меня возникли проблемы с использованием MapMaker из Google-гуавы. Вот код:
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>>
(и в соответствии с изменениями в остальной части кода: слушатель и пут), я вижу, что выселения происходят, и код просто работает, и значения собираются мусором.
Во всей документации, включая эту: http://guava-libraries.googlecode.com/svn/tags/release09/javadoc/index.html, в явном виде не упоминается SoftReferences. Разве реализация Map не должна оборачивать значения в SoftReference при вызове put? Я действительно смущен по поводу предполагаемого использования.
Я использую guava r09.
Может кто-нибудь объяснить, что я делаю неправильно, и почему мои предположения неверны?
С наилучшими пожеланиями, Вуек
1 ответ
Вы используете один и тот же объект для ключа и значения, поэтому он очень доступен в качестве ключа и не подходит для сборки мусора, несмотря на то, что значение легко достижимо:
map.put(s, s);
Попробуйте использовать разные экземпляры:
map.put(s, new String(s));