Je souhaite utiliser MapMaker pour créer une carte mettant en cache des objets volumineux, , qui doivent être supprimés du cache si la mémoire est insuffisante. Ce petit programme de démonstration semble fonctionner très bien:Utilisation de MapMaker pour créer un cache
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();
}
}
Cependant, quand je fais la même chose dans mon application réelle, les entrées sont essentiellement retirées de la cache dès qu'ils sont ajoutés. Dans mon application réelle , j'utilise également des entiers comme clés, et les valeurs mises en cache sont blocs d'archive lus à partir du disque qui contient des données. Autant que je le comprends, les références faibles sont ramassées à la poubelle dès qu'elles sont n'est plus utilisé, donc cela semble logique car les clés sont faibles références . Si je crée la carte comme ceci:
data = new MapMaker()
.softValues()
.makeMap();
Les entrées ne sont jamais et ramasse-miettes je reçois une erreur hors de la mémoire dans mon programme de test. La méthode finalize sur les entrées TestValue n'est jamais appelée. Si je change la méthode d'essai à ce qui suit:
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) {
}
}
}
entrées sont supprimées du cache et le finaliseur sur les objets TestValue est appelé, mais après un certain temps je reçois aussi un hors-mémoire erreur . Donc, ma question est: quelle est la bonne façon d'utiliser MapMaker pour créer une carte qui peut être utilisée comme cache? Pourquoi mon programme de test ne supprime-t-il pas les entrées dès que possible si j'utilise weakKeys? Est-il possible de ajouter une file d'attente de référence à la carte de cache?
quelqu'un peut-il modifier le code pour le rendre plus facile à lire? – nanda
Je suis un peu surpris par cela. J'ai utilisé 'softValues' exactement de la même manière et cela a bien fonctionné, avec' SoftReference' étant effacé quand la mémoire est faible. – finnw