13

我正在寻找一个简单的内存(和进程内)缓存,用于查询数据的短期缓存(但短期含义超出请求/响应,即会话边界)。EhCache 可能会起作用,但看起来它可能无法提供我需要的一件事:不是对缓存对象数量的限制,而是对缓存数据消耗的内存量的(近似)限制。

我知道在没有序列化的情况下很难计算出给定对象的确切内存使用情况(在一般情况下,我想避免这种情况,因为它的速度很慢,违背了我的使用目的),我可以自己提供大小估计。

那么:是否有一个简单的开源 Java 缓存允许定义缓存对象的“权重”,以限制缓存的内容数量?

编辑(2010 年 11 月):值得一提的是,有一个名为Java CacheMate的新项目试图解决这个问题,以及其他一些改进想法(多级内存进程内缓存)

4

8 回答 8

3

我同意 Paul 的观点,这通常可以通过使用软引用缓存来解决,尽管它可能会比您喜欢的更早地驱逐条目。通常可以接受的解决方案是使用一个普通的缓存,它驱逐到软缓存,并在可能的情况下恢复未命中的条目。这种受害者缓存方法效果很好,给你一个较低的标准,但如果可用内存可用,则会有额外的好处。

内存大小可以通过启用 Java 代理来确定,使用 SizeOf 实用程序 ( http://sourceforge.net/projects/sizeof ) 时使用非常简单。我只将它用于调试目的,我建议在将其用于正常使用之前对开销进行基准测试。

在我的缓存库中,我计划在实现核心算法后添加插入评估器的功能。这样,您可以将集合存储为值,但通过所有集合大小的总和来绑定缓存。我已经看到无限集合作为缓存中的值会导致 OutOfMemoryExceptions,因此控制非常方便。

如果你真的需要这个,我建议不要这样做,我们可以增强我当前的实现来支持这个。你可以给我发电子邮件,ben.manes-at-gmail.com。

于 2009-03-28T20:54:15.687 回答
2

如何使用启用 LRU 算法的简单 LinkedHashMap 并将所有带有 SoftReference 的数据放入其中......例如 cache.out(key, new SoftReference(value)) ?

这会将您的缓存限制为可用内存量,但不会杀死程序的其余部分,因为Java会在有内存需求时删除软引用......不是全部......通常是最旧的...... 如果您将引用队列添加到您的实现中,您还可以从映射中删除停顿条目(只有键,没有值)。

这将使您免于计算条目的大小并跟踪总和。

于 2009-03-30T00:03:47.407 回答
2

EhCache V2.5 目前提供了一种可以根据缓存的内存大小进行封顶的解决方案。有关更多详细信息,请查看EhCache 2.5 文档

于 2011-11-13T19:19:32.067 回答
0

这不仅难以衡量——也难以定义。

假设两个缓存条目引用同一个字符串 - 它们是否计算该字符串的大小,尽管从缓存中删除它们中的任何一个都不会使字符串符合垃圾回收条件?它们都不计算大小,尽管如果它们都从缓存中删除,则字符串可能有资格被收集?如果不在缓存中的另一个对象引用了该字符串怎么办?

如果您可以准确地描述您感兴趣的尺寸,则可以通过编程方式确定它 - 但我怀疑您会发现甚至很难确定您想要什么。

于 2009-03-27T17:58:46.210 回答
0

除了猜测对象的内存使用情况外,对于一个合理的算法,您还需要猜测重新创建它的成本。一个合理的猜测是娱乐成本大致与内存大小成正比。所以这些因素相互抵消,你不需要。一个简单的算法可能会更好。

于 2009-03-27T18:09:54.607 回答
0

如果您无法做出任何估计 - 编写一个缓存驱逐策略,该策略基于 JVM 堆大小(从系统轮询)或由来自孤立对象(在 GC 上)的 finalize() 调用触发。

于 2009-03-27T18:33:35.017 回答
0

可以为缓存的内存使用定义一个有意义的度量。您可以计算 : "retained size"。不幸的是,计算保留大小的成本大致与完整 GC 一样高,因此可能不是一种选择。在某些 JVM 语言(clojure?)中,理论上您可以确保缓存中的任何对象都不会被外部对象引用,然后您可以监控缓存的实际大小。

于 2009-03-30T08:16:06.270 回答
-1

完成这项工作的是 java.lang.ref.SoftReference 。通常,您扩展 SoftReference 类,以便子类包含键。

于 2009-03-27T19:09:35.650 回答