【发布时间】:2010-07-09 07:25:38
【问题描述】:
我想使用 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,请尽快输入条目?是否有可能 向缓存映射添加引用队列?
【问题讨论】:
-
有人可以编辑代码以使其更易于阅读吗?
-
对此我有点惊讶。我以完全相同的方式使用
softValues,它运行良好,当内存不足时,SoftReference被清除。
标签: guava