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

是否有任何Java缓存可以限制内存中缓存的内存使用,而不仅仅是实例数?,java,caching,memory-management,ehcache,Java,Caching,Memory Management,Ehcache,我正在寻找一个简单的内存(和进程中)缓存,用于查询数据的短期缓存(但短期含义超出请求/响应,即会话边界)。 EhCache可能会工作,但它似乎没有提供我需要的一件事:不限制缓存对象的数量,而是(近似)限制缓存数据消耗的内存量 我知道,如果不进行序列化,很难计算出给定对象的确切内存使用情况(一般情况下,我希望避免这种情况,因为它的速度太慢,无法满足我的使用目的),我自己也可以提供大小估计 那么:是否有一个简单的开源java缓存允许定义缓存对象的“权重”,以限制缓存的内容量 编辑(2010年11月)

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

我知道,如果不进行序列化,很难计算出给定对象的确切内存使用情况(一般情况下,我希望避免这种情况,因为它的速度太慢,无法满足我的使用目的),我自己也可以提供大小估计

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


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

这不仅难以衡量,而且难以定义

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


如果你能准确地描述你感兴趣的大小,也许可以通过编程来确定它——但我怀疑你会发现,甚至很难确定你到底想要什么。

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

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

执行此任务的是java.lang.ref.SoftReference。通常,您会扩展SoftReference类,使子类包含键。

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

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

在我的缓存库中,我计划在核心算法实现后添加插入计算器的功能。通过这种方式,可以将集合存储为值,但通过所有集合大小的总和绑定缓存。我见过无限的集合,因为缓存中的值会导致OutOfMemoryException,所以控制非常方便


如果您真的需要此功能,我建议您不要这样做,我们可以增强当前的实现以支持此功能。你可以通过gmail.com给我发电子邮件,ben.manes。

使用一个简单的LinkedHashMap,启用LRU算法,然后将所有带有软引用的数据放在其中,怎么样。。。例如cache.out(key,new SoftReference(value))

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


这将使您不必计算条目的大小和跟踪总和。

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

EhCache V2.5目前提供了一种解决方案,可以根据缓存的内存大小设置上限。有关签出的更多详细信息,Hi Jon,您的评论总体上是有意义的,但是有一种有意义的方法来计算缓存的大小(保留大小)。请看下面我的答案。我对通用解决方案不感兴趣——对于我的用例,是的,我可以很容易地确定大致的大小。我同意,在一般情况下,这当然是不可能的。没关系,我不需要解决那个问题好的,所以你需要按大小加权。您是否也希望按上次使用的时间进行加权?你希望它们如何平衡?如果没有last time元素,您可以在HashMap旁边使用PriorityQueue来确定要逐出什么。保留一个总数,这样你就知道什么时候该驱逐了。对我来说,优先考虑驱逐什么,以及缓存的总边界仍然是两个独立的问题;LRU是好的,即使它意味着一个大项目是消耗整个缓存“配额”。所以,是的,我同意,分开订购和排队是有意义的。谢谢但是,这一措施没有考虑到这样一个事实,即将两个条目中的任何一个从缓存中推出都可能会释放几乎没有空间,但是将这两个条目都推出可能会释放大量空间。嗨,Jon,您只需要计算整个缓存的“保留集”。您模拟缓存“根”对象(现在假设它是