我刚刚通过搜索缓存API找到了Guava(它非常适合我的需求)。 但是在阅读wiki和Javadoc时出现了一个问题 - CacheBuilder可以采用什么设置的默认值? Javadoc状态“这些功能都是可选的”和“使用默认设置构造一个新的CacheBuilder实例,包括强密钥,强值,并且不会自动驱逐任何类型。”
在我看来,maximumSize
的良好默认值相对于Runtime.getRuntime().freeMemory();
最后,我想要一个使用给定系统上可用内存的缓存。所以我需要一个驱逐策略,询问有多少freeMemory()
可用(可能相对于Runtime.getRuntime().maxMemory()
)
答案 0 :(得分:6)
实际上,可用内存并不是缓存驱逐度量的最佳选择。原因是垃圾收集。耗尽空闲内存可能只意味着现在是垃圾收集器运行的时候了,之后你会突然有大量的空闲内存。所以你不想要从缓存中删除东西只是因为你有大量的垃圾。
一种选择是使用softValues()
,但我强烈建议不要这样做,因为软引用确实会影响生产性能。
正确的做法是仔细选择一个maximumSize
,它实际上限制了缓存将占用的内存总量。如果条目占用可变数量的空间,那么您可以使用maximumWeight
来对其进行建模。
答案 1 :(得分:1)
我让我质疑同样的事情,在网上找不到任何东西。所以我做了这个非常原始的测试。 我编写了一段代码,创建了一个具有最基本设置的LocalCache(没有最大大小,没有驱逐策略,没有),并且在无限循环中将内容放入缓存中。并通过VisualVm监视它以检查堆使用情况。
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
public class CacheTest {
public static void main(String[] args) {
Cache<String, String> cache = CacheBuilder.newBuilder().build();
int counter = 0;
while(true){
cache.put("key"+counter++,"value");
System.out.println("size:"+cache.size());
}
}
}
从下图中可以看出,内存使用量增长到最大可用空间并变为常量。我等了几分钟,没有出现OutOfMemoryError。发生的事情是,几秒钟之后,一个新条目被添加到地图中,因此将来可能会出现错误。
结论:您不必设置maximumSize值,但我建议您使用某种逐出策略(expireAfterAccess或expireAfterWrite)来清理缓存并避免出现OutOfMemoryError。并且还要避免降低缓存的性能。
答案 2 :(得分:0)
取自 LocalCache 类的代码
package com.google.common.cache;
@GwtCompatible(
emulated = true
)
class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {
int initialCapacity = Math.min(builder.getInitialCapacity(), 1073741824);
if (this.evictsBySize() && !this.customWeigher()) {
initialCapacity = Math.min(initialCapacity, (int)this.maxWeight);
this.initTable(this.newEntryArray(initialCapacity));
希望这能回答最初的尺寸问题。