2010-09-28 51 views
0

我们收集了随着时间推移增长得相当大的对象。我们实施了缓存策略来帮助缓解这一问题,但是,如果在启动时没有分配足够的内存,我们仍然会在运行时耗尽堆空间。动态分配缓存大小以缓解堆空间错误

是否有标准的机制来减少运行时缓存的大小以消除这些OutOFMemory错误?这样,如果我们的进程以比正常情况更小的内存片开始,我们可以希望避免服务器死机。

我意识到这是一个错误类型,因此不应该被捕获/处理,因为它通常表示更严重的问题。

是它具有一些如下的简单:

private static final long RECOMMENDED_MEMORY = 1073741824L; //Example 1 Gig 
private static int recommendedCacheSize = 100; //Example of 100 items 
long heapSize = Runtime.getRuntime().totalMemory(); 
double size = Math.floor((double) heapSize/RECOMMENDED_MEMORY * recommendedCacheSize); 
recommendedCacheSize = ++size; 
+0

注意:这是在Tomcat中运行。 – Scott 2010-09-28 14:31:52

+0

缓存是使用软参考还是弱参考构建的? – 2010-09-28 14:41:34

回答

0

为什么不使用被设计为real cache的东西?

尽管可以使用软引用来实现对内存敏感的缓存,但这种缓存往往会使对象在内存中保留太久(增加GC负载)。弱引用不适用于缓存,因为它们被清除的可能性要高得多(实际上,每个GC都会清除它们)。

0

我怀疑缓存实现不保持WeakReferenceSoftReference对象,它们在一个Java对象缓存通常采用的缓存。对缓存使用软或弱引用是非常重要的,否则就有可能引发OOME(内存不足错误)。

使用软/弱引用的理由是垃圾收集器将尝试收集这些对象,以防内存不足。使用强引用(普通对象引用)来存储对缓存中对象的引用,将会阻止内存被回收。

但是,即使您使用弱/软引用,您也会得到OOME,我怀疑您的GC没有很好地调整。看起来您的应用程序会突然遇到内存消耗,导致OOME状况。这种情况是不太可能的,但是可能的,特别是如果先前调用GC没有清除足够的内存(最终消耗在下一次消耗中)。

+0

我们的对象缓存正在使用Apache Commons KeyedObjectPool,所以我们应该符合这个标准。我相信我们的默认设置太高的真正问题。这个想法是允许每个开发人员根据他们机器的每一种能力都有不同的缓存大小。 – Scott 2010-09-28 15:31:00

+0

@Scott,除非你使用Commons Pool的SoftReferenceObjectPool,否则你不会在下面使用软引用。此外,Commons Pool是一个池化实现,而不是缓存。它有自己的驱逐算法,显然与GC不同。因此,您可能想要检查是否有任何驱逐对象 - 没有任何驱逐将解释OOME。 – 2010-09-28 15:48:25

+0

如果我们将maxIdle设置为1,并将whenExhaustedAction设置为BLOCK,则不应该将其用作缓存吗?我们正在使用GenericKeyedObjectPool – Scott 2010-09-28 15:54:22