如何使用可用 RAM 有效地缓存 Java 中的对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2158868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I efficiently cache objects in Java using available RAM?
提问by sanity
I need to cache objects in Java using a proportion of whatever RAM is available. I'm aware that others have asked this question, but none of the responses meet my requirements.
我需要使用一定比例的可用 RAM 在 Java 中缓存对象。我知道其他人已经问过这个问题,但没有一个回答符合我的要求。
My requirements are:
我的要求是:
- Simple and lightweight
- Not dramatically slower than a plain HashMap
- Use LRU, or some deletion policy that approximates LRU
- 简单轻便
- 并不比普通的 HashMap 慢得多
- 使用 LRU,或一些近似 LRU 的删除策略
I tried LinkedHashMap, however it requires you to specify a maximum number of elements, and I don't know how many elements it will take to fill up available RAM (their sizes will vary significantly).
我尝试过 LinkedHashMap,但是它要求您指定最大元素数,而且我不知道填充可用 RAM 需要多少个元素(它们的大小会有很大差异)。
My current approach is to use Google Collection's MapMaker as follows:
我目前的方法是使用 Google Collection 的 MapMaker,如下所示:
Map<String, Object> cache = new MapMaker().softKeys().makeMap();
This seemed attractive as it should automatically delete elements when it needs more RAM, however there is a serious problem: its behavior is to fill up all available RAM, at which point the GC begins to thrash and the whole app's performance deteriorates dramatically.
这看起来很有吸引力,因为它应该在需要更多 RAM 时自动删除元素,但是有一个严重的问题:它的行为是填满所有可用 RAM,此时 GC 开始抖动,整个应用程序的性能急剧下降。
I've heard of stuff like EHCache, but it seems quite heavy-weight for what I need, and I'm not sure if it is fast enough for my application (remembering that the solution can't be dramatically slower than a HashMap).
我听说过 EHCache 之类的东西,但它对于我需要的东西来说似乎很重要,而且我不确定它对于我的应用程序是否足够快(记住该解决方案不能比 HashMap 慢得多) .
采纳答案by Jonathan
I've got similar requirements to you - concurrency (on 2 hexacore CPUs) and LRU or similar - and also tried Guava MapMaker. I found softValues() much slower than weakValues(), but both made my app excruciatingly slow when memory filled up.
我对您有类似的要求 - 并发(在 2 个六核 CPU 上)和 LRU 或类似的 - 并且还尝试了 Guava MapMaker。我发现 softValues() 比weakValues() 慢得多,但是当内存填满时,两者都使我的应用程序极其缓慢。
I tried WeakHashMap and it was less problematic, oddly even faster than using LinkedHashMap as an LRU cache via its removeEldestEntry() method.
我尝试了 WeakHashMap,它的问题更少,甚至比通过其 removeEldestEntry() 方法使用 LinkedHashMap 作为 LRU 缓存还要快。
But by the fastest for me is ConcurrentLinkedHashMapwhich has made my app 3-4 (!!) times faster than any other cache I tried. Joy, after days of frustration! It's apparently been incorporated into Guava's MapMaker, but the LRU feature isn't in Guava r07 at any rate. Hope it works for you.
但对我来说最快的是ConcurrentLinkedHashMap,它使我的应用程序比我尝试过的任何其他缓存快 3-4 (!!) 倍。快乐,经过几天的挫折!它显然已被合并到 Guava 的 MapMaker 中,但无论如何,LRU 功能都不在 Guava r07 中。希望对你有效。
回答by stacker
I've implemented serval caches and it's probably as difficult as implementing a new datasource or threadpool, my recommendation is use jboss-cache or a another well known caching lib. So you will sleep well without issues
我已经实现了 serval 缓存,它可能和实现新的数据源或线程池一样困难,我的建议是使用 jboss-cache 或另一个众所周知的缓存库。所以你会睡得很好没有问题
回答by Pascal Thivent
I've heard of stuff like EHCache, but it seems quite heavy-weight for what I need, and I'm not sure if it is fast enough for my application (remembering that the solution can't be dramatically slower than a HashMap).
我听说过 EHCache 之类的东西,但它对于我需要的东西来说似乎很重要,而且我不确定它对于我的应用程序是否足够快(记住该解决方案不能比 HashMap 慢得多) .
I really don't know if one can say that EHCacheis heavy-weight. At least, I do not consider EHCache as such, especially when using a Memory Store(which is backed by an extended LinkedHashMapand is of course the the fastest caching option). You should give it a try.
真不知道能不能说EHCache是重量级的。至少,我不考虑 EHCache,尤其是在使用内存存储时(它由扩展支持LinkedHashMap,当然是最快的缓存选项)。你应该试一试。
回答by Kevin Bourrillion
I believe MapMakeris going to be the only reasonable way to get what you're asking for. If "the GC begins to thrash and the whole app's performance deteriorates dramatically," you should spend some time properly setting the various tuning parameters. This document may seem a little intimidating at first, but it's actually written very clearly and is a goldmine of helpful information about GC:
我相信MapMaker这将是获得您所要求的唯一合理方式。如果“GC 开始抖动,整个应用程序的性能急剧下降”,您应该花一些时间正确设置各种调整参数。这份文档乍一看可能有点吓人,但实际上写得很清楚,是有关 GC 有用信息的金矿:
http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf
http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf
回答by omerkudat
I don't know if this would be a simple solution, especially compared with EHCache or similar, but have you looked at the Javolution library? It is not designed for as such, but in the javolution.contextpackage they have an Allocator pattern which can reuse objects without the need for garbage collection. This way they keep object creation and garbage collection to a minimum, an important feature for real-time programming. Perhaps you should take a look and try to adapt it to your problem.
我不知道这是否是一个简单的解决方案,尤其是与 EHCache 或类似的相比,但您是否看过Javolution 库?它不是为此而设计的,但在javolution.context包中它们有一个分配器模式,可以重用对象而无需垃圾收集。通过这种方式,他们将对象创建和垃圾收集保持在最低限度,这是实时编程的一个重要特性。也许您应该看看并尝试使其适应您的问题。
回答by hqt
Caching something, SoftReferencemaybe the best way until now I can imagine.
缓存一些东西,SoftReference也许是我能想象到的最好的方法。
Or you can reinvent an Object-pool. That every object you doesn't use, you don't need to destroy it. But it to save CPU rather than save memory
或者你可以重新发明一个对象池。每一个你不使用的对象,你都不需要销毁它。但它是为了节省 CPU 而不是节省内存
回答by ralph
In the past I have used JCS. You can set up the configurationto try and meet you needs. I'm not sure if this will meet all of your requirements/needs but I found it to be pretty powerful when I used it.
过去我使用过JCS。您可以设置配置以尝试满足您的需求。我不确定这是否能满足您的所有要求/需要,但我在使用它时发现它非常强大。
回答by pgras
You cannot "delete elements" you can only stop to hard reference them and wait for the GC to clean them, so go on with Google Collections...
你不能“删除元素”,你只能停下来硬引用它们并等待 GC 清理它们,所以继续使用 Google Collections ...
回答by Eli Acherkan
I'm not aware of an easy way to find out an object's size in Java. Therefore, I don't think you'll find a way to limit a data structure by the amount of RAM it's taking.
我不知道在 Java 中找出对象大小的简单方法。因此,我认为您不会找到一种方法来通过它所占用的 RAM 量来限制数据结构。
Based on this assumption, you're stuck with limiting it by the number of cached objects. I'd suggest running simulations of a few real-life usage scenarios and gathering statistics on the types of objects that go into the cache. Then you can calculate the statistically average size, and the number of objects you can afford to cache. Even though it's only an approximation of the amount of RAM you want to dedicate to the cache, it might be good enough.
基于这个假设,您只能通过缓存对象的数量来限制它。我建议对一些现实生活中的使用场景进行模拟,并收集有关进入缓存的对象类型的统计信息。然后您可以计算统计平均大小,以及您可以缓存的对象数量。尽管它只是您想要专用于缓存的 RAM 量的近似值,但它可能已经足够了。
As to the cache implementation, in my project (a performance-critical application) we're using EhCache, and personally I don't find it to be heavyweight at all.
至于缓存实现,在我的项目(一个性能关键的应用程序)中,我们使用的是 EhCache,我个人认为它根本不是重量级的。
In any case, run several tests with several different configurations (regarding size, eviction policy etc.) and find out what works best for you.
在任何情况下,使用几种不同的配置(关于大小、驱逐策略等)运行多个测试,找出最适合您的方法。
回答by Kevin
This seemed attractive as it should automatically delete elements when it needs more RAM, however there is a serious problem: its behavior is to fill up all available RAM
这看起来很有吸引力,因为它应该在需要更多 RAM 时自动删除元素,但是有一个严重的问题:它的行为是填满所有可用的 RAM
Using soft keys just allows the garbage collector to remove objects from the cache when no other objects reference them (i.e., when the only thing referring to the cache key is the cache itself). It does not guarantee any other kind of expulsion.
使用软键仅允许垃圾收集器在没有其他对象引用它们时(即,当唯一引用缓存键的是缓存本身时)从缓存中删除对象。它不保证任何其他类型的驱逐。
Most solutions you find will be features added on top of the java Map classes, including EhCache.
您找到的大多数解决方案都是在 Java Map 类之上添加的功能,包括 EhCache。
Have you looked at the commons-collectionsLRUMap?
你看过公共收藏LRUMap 吗?
Note that there is an open issueagainst MapMaker to provide LRU/MRU functionality. Perhaps you can voice your opinion there as well
请注意,有一个针对 MapMaker 提供 LRU/MRU 功能的未决问题。也许你也可以在那里发表你的意见

