任何可以限制内存缓存的内存使用的Java缓存,而不仅仅是实例计数?

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

我知道很难在没有序列化的情况下找出给定对象的确切内存使用情况(我希望在一般情况下避免由于其缓慢而使我的用途失败),并且我很自己必须提供大小估计。

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

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

我同意保罗的说法,这通常是通过使用软参考缓存来解决的,尽管它可能比你更喜欢的方式驱逐条目。 通常可接受的解决方案是使用驱逐到软缓存的普通缓存,并在可能的情况下恢复未命中的条目。 这种受害者缓存方法非常有效,如果有可用内存,可以为您提供更低的条件,但可以获得额外的好处。

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

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

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

如何使用一个简单的LinkedHashMap启用LRU算法并将所有数据与SoftReference放在一起…比如cache.out(key,new SoftReference(value))??

这会将缓存限制为可用内存量但不会终止程序的其余部分,因为Java会在存在内存需求时删除软引用…不是全部…最旧的第一个…通常。 如果向实现添加引用队列,还可以从映射中删除停顿条目(仅键,无值)。

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

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

这不仅难以衡量 – 很难定义。

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

如果你可以准确地描述你感兴趣的大小,那么就有可能以编程方式确定它 – 但我怀疑你甚至很难确定你想要的确切内容。

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

如果您无法进行任何估计 – 编写基于JVM堆大小(从系统轮询)或由finalize()触发的高速缓存驱逐策略 – 从孤立对象(在GC上)调用。

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

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