google common cache - maximumSize的默认值(和其他“可选”设置) - 想要一个使用所有“可用”内存的缓存

时间:2012-02-10 14:06:46

标签: java caching memory guava heap-memory

我刚刚通过搜索缓存API找到了Guava(它非常适合我的需求)。 但是在阅读wikiJavadoc时出现了一个问题 - CacheBuilder可以采用什么设置的默认值? Javadoc状态“这些功能都是可选的”和“使用默认设置构造一个新的CacheBuilder实例,包括强密钥,强值,并且不会自动驱逐任何类型。”

在我看来,maximumSize的良好默认值相对于Runtime.getRuntime().freeMemory();

最后,我想要一个使用给定系统上可用内存的缓存。所以我需要一个驱逐策略,询问有多少freeMemory()可用(可能相对于Runtime.getRuntime().maxMemory()

3 个答案:

答案 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。发生的事情是,几秒钟之后,一个新条目被添加到地图中,因此将来可能会出现错误。

Heap Dump

结论:您不必设置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));

希望这能回答最初的尺寸问题。