Java内存感知缓存

时间:2011-08-30 15:56:58

标签: java caching memory jvm out-of-memory

我正在寻找一些想法,如果有人知道的话,可能已经有了一些具体的实现,但我愿意自己编写想要的缓存。

我希望有一个缓存只缓存我配置的gigs。与应用程序的其余部分相比,缓存部分将使用几乎100%的内存,因此我们可以将应用程序的已用内存概括为缓存大小(+垃圾)。

是否有方法可以猜测使用了多少内存?或者依靠软指针更好吗?软指针和总是在jvm内存限制的顶部运行可能是非常无效的,有很多cpu周期用于内存清理?我可以对现有对象进行一些分析,例如myObject.getMemoryUsage()

LinkedHashMap有足够的缓存命中率,所以我不需要编写一些战略缓存怪物,但我不知道如何正确解决这个问题。有任何想法吗?我不希望OOME在任何地方飞行。

什么是最好的实践?

4 个答案:

答案 0 :(得分:2)

SoftReference不是一个好主意,因为它们往往更清晰。这意味着当您从GC中获得性能影响时,您也必须重新构建缓存。

您可以使用Instrumentation.getObjectSize()来获取Object的浅尺寸并使用反射来获得深度。然而,这样做相对昂贵,而不是你想经常做的事情。

为什么不能将大小限制为多个对象?事实上,我会从最简单的缓存开始,只添加你真正需要的东西。

LRU cache in Java.

编辑:跟踪您正在使用多少内存的一种方法是序列化值并将其存储为byte []。这可以为您提供相当精确的控制,但是可以将您的解决方案减慢多达1000倍。 (没有什么是免费的;)

答案 1 :(得分:1)

我建议使用Java Caching System。虽然如果你想自己动手,我不知道有什么方法可以在内存中获得对象大小。最好的办法是扩展AbstractMap并将值包装在SoftReferences中。然后,您可以将Java堆大小设置为所需的最大大小。但是,您的实现还必须查找并清除过时数据。使用JCS可能更容易。

答案 2 :(得分:1)

SoftReferences的问题在于它们为垃圾收集器提供了更多的工作。虽然它不符合您的要求,但HBase有一个非常有趣的策略,以防止缓存导致垃圾收集暂停:它们将缓存存储在本机内存中:

您的用例的良好开端是将所有数据存储在磁盘上。它可能看起来很幼稚,但由于I / O缓存,经常访问的数据将驻留在内存中。我强烈建议您从Varnish缓存系统中阅读这些架构说明:

答案 3 :(得分:0)

我发现的最佳做法是尽可能将缓存功能委托给Java之外。 Java可能很好地管理内存,但是专用缓存系统应该用于简单的LRU缓存以外的任何东西。

GC启动时费用很高。

EHCache是​​我所知道的最受欢迎的之一。另一个答案的Java缓存系统也很好。

但是,我通常将该工作卸载到底层函数(通常是应用程序服务器的JPA持久层,我让它在那里处理,所以我不必在应用程序层上处理它。)

如果您要缓存其他数据,例如网络请求,http://hc.apache.org/httpclient-3.x/也是另一个不错的选择。

但是,只要记住你也有“文件系统”,写入你检索的文件系统数据绝对没有错。由于ByteArrayOutputStreams的使用不当,我已多次使用该技术修复内存不足错误