如何利用可用内存在Java中高效缓存对象?

26

我需要使用Java在可用内存的一部分上缓存对象。我知道其他人也提过这个问题,但是没有一个答案符合我的需求。

我的要求是:

  • 简单而轻量
  • 不比纯HashMap明显地慢
  • 使用LRU或某种近似于LRU的删除策略

我尝试了LinkedHashMap,但它需要您指定最大元素数量,而我不知道需要多少元素才能填满可用RAM(它们的大小将有很大差异)。

我的当前方法是使用Google Collections的MapMaker如下:

Map<String, Object> cache = new MapMaker().softKeys().makeMap();

这看起来很有吸引力,因为它应该在需要更多内存时自动删除元素,然而存在一个严重的问题:它的行为是填满所有可用的内存,此时GC开始大量换页,整个应用程序的性能急剧恶化。

我听说过EHCache之类的东西,但对于我所需的东西来说似乎太重了,而且我不确定它是否足够快(记住解决方案不能比HashMap慢得多)。


你正在缓存哪些对象?我不太明白为什么你会关心缓存的性能,因为一旦你使用到过期策略,你将会比使用普通Map更加耗费资源。EHCache是一个成熟的缓存库,通过Spring进行配置也并不复杂,使用起来和Map一样简单。 - beny23
这些对象的大小从大约1kb到可能达到10kbs不等。我担心性能问题,因为从缓存中检索对象是非常CPU密集型过程的内部循环。如果速度慢,它会将我的应用程序所需的时间从几分钟增加到几个小时。 - sanity
使用softKeys()方法时,如果使用equals()方法,则无法命中缓存;只有在使用引用相等性来查找对象时,才能命中缓存。如果需要通过equals()方法进行缓存命中,请改用softValues()方法。 - Blair Zajac
可能是Java中易于使用的LRU缓存的重复问题。 - Mifeet
12个回答

0

缓存某些东西,SoftReference 可能是我现在能想到的最好的方法。

或者你可以重新发明一个对象池。每个你不再使用的对象,你都不需要销毁它。但这样做是为了节省 CPU 而不是节省内存。


-3

假设您希望缓存是线程安全的,那么您应该查看Brian Goetz的书《Java并发实践》中的缓存示例。我强烈推荐这本书。


那并没有真正回答他的问题。 - danben
@danben:我同意。但线程安全性是他必须考虑的问题。 - Steve Emmerson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接