java - 知道可达性的缓存

标签 java caching guava weak-references soft-references

我想要一个最大保留容量为 N 的缓存。我允许它最多容纳 N 个对象,否则这些对象将有资格进行 GC。现在,如果我的应用程序本身当前持有对先前添加到缓存中的对象的 N+1 强引用,那么我希望缓存也持有 N+1。为什么?因为缓存不会比其他情况下更长时间地阻止第 N+1 个对象被收集,而且我可以用更大的哈希表来换取更多的缓存命中。

另一种说法是,我想要一个对象缓存,它保留添加到其中的所有对象,同时保持强可达性,并且还保留足够的非强可达性对象以保持其大小== N。

示例

我们创建了一个 N=100 的缓存。大小从 0 开始。添加 150 个对象,大小为 150。其中 100 个对象变为非强可达性(弱可达性、弱可达性等)。缓存逐出其中 50 个并保留 50 个,大小为 100。添加了 49 个更强可达对象。大小仍然是 100,但现在其中 99 个是强可达的,只有一个是非强可达的。所发生的情况是 49 个旧的、非强可达对象被新的 49 个对象替换,因为新对象是强可达的。

动机

我怀疑对于许多用例来说这实际上是一个直观的事情。通常,缓存的容量会牺牲缓存命中概率来保证最大内存使用率。了解其所保存的对象的可达性后,缓存可以提供更高的缓存命中概率,而无需更改其最大内存使用保证。

麻烦

我担心这在 JVM 上是不可能的。我希望别人告诉我,但如果你知道事实是不可能的,如果有理由的话,我也会接受这个答案。

最佳答案

您可以将条目添加到配置为 LRU 或 FIFO 缓存的 LinkedHashMap。您也可以拥有 WeakHashMap。如果将 key 添加到两个映射,LHM 将阻止清理,即使它位于 WHM 中。一旦 LHM 丢弃 key ,它可能会也可能不会在 WHM 中。

例如

private final int retainedSize;
private final Map<K,V> lruMap = new LinkedHashMap<K, V>(16, 0.7f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > retainedSize;
    }
};
private final Map<K,V> weakMap = new WeakHashMap<K, V>();

public void put(K k, V v) {
    lruMap.put(k, v);
    weakMap.put(k,v);
}

public V get(K k) {
    V v = lruMap.get(k);
    return v == null ? weakMap.get(k) : v;
}

这样做的原因之一是 WeakHashMap 会一下子变得更清晰,所以你的命中率会急剧下降。这种方法可以确保您在遭遇 Full GC 后,在尝试追赶时性能不会下降太多。 ;)

关于java - 知道可达性的缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12326847/

相关文章:

java - Spark 1.4.0 java.lang.NoSuchMethodError : com. google.common.base.Stopwatch.elapsedMillis()J

java - Spring Batch - 如何重试,然后在重试失败时跳过

java - WebDriver 与 ChromeDriver

c# - 在 .Net 中缓存大量数据是否可以接受?

python - 如何使用 joblib.Memory 缓存 Python 类的成员函数的输出

guava - Datastax Cassandra 驱动程序抛出 CodecNotFoundException

JavaFX 绑定(bind)到嵌套列

java - 为 'between' 字符串创建 Hibernate 限制

java - 是否有 XML 注释可用于将类属性组合在一个公共(public)元素下?

java - 缓存安全信息安全吗?