我的情况是我有 Grails 2.1.2 应用程序,并希望使用缓存插件和缓存-ehcache 插件作为实现来引入方法级缓存。
我的缓存配置为像这样在内存中:
grails.cache.config = {
cache {
name 'homePageCache'
enabled true
eternal false
pinning {
store 'localMemory'
}
}
我有一个像这样的方法,它只需要 int 参数,所以密钥生成不是问题:
@Cacheable('homePageCache')
TubeVideoPagingArray findHomePageOfVideos(int pageSize) {
我的问题java.lang.OutOfMemoryError: Java heap space
是调用此方法时出现异常。原因是 ehcache 使用一个名为 ObjectGraphWalker 的类计算将要放入缓存的对象的大小,该类遍历对象图并对大小求和。
我为 ehcache 设置了调试级别日志记录,并看到大量与这些类似的行:
2014-04-17 13:27:13,470 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'bigDecimalMultiplier' of class java.text.DecimalFormat
2014-04-17 13:27:13,470 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'digitList' of class java.text.DecimalFormat
2014-04-17 13:27:13,470 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'positivePrefixFieldPositions' of class java.text.DecimalFormat
2014-04-17 13:27:13,470 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'positiveSuffixFieldPositions' of class java.text.DecimalFormat
2014-04-17 13:27:13,470 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'negativePrefixFieldPositions' of class java.text.DecimalFormat
2014-04-17 13:27:13,470 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'negativeSuffixFieldPositions' of class java.text.DecimalFormat
2014-04-17 13:27:13,470 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'currency' of class java.text.DecimalFormatSymbols
2014-04-17 13:27:13,488 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'metaClass' of class org.codehaus.groovy.grails.plugins.converters.codecs.XMLCodec$__clinit__closure1
2014-04-17 13:27:13,491 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'metaClass' of class org.codehaus.groovy.grails.plugins.codecs.URLCodec$__clinit__closure2
2014-04-17 13:27:13,492 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'metaClass' of class org.codehaus.groovy.grails.plugins.codecs.URLCodec$__clinit__closure1
2014-04-17 13:27:13,494 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'metaClass' of class org.codehaus.groovy.grails.plugins.codecs.SHA256Codec$__clinit__closure2
2014-04-17 13:27:13,495 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'metaClass' of class org.codehaus.groovy.grails.plugins.codecs.SHA256Codec$__clinit__closure1
2014-04-17 13:27:13,498 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'metaClass' of class org.codehaus.groovy.grails.plugins.codecs.JavaScriptCodec$__clinit__closure1
2014-04-17 13:27:13,501 DEBUG [org.ehcache.sizeof.ObjectGraphWalker] SizeOf engine walking transient field 'metaClass' of class org.codehaus.groovy.grails.plugins.codecs.MD5BytesCodec$__clinit__closure2
很明显,它遍历了一堆元类,这导致它到其他元类结束上帝知道在哪里......
Ehcache 有一种机制来配置这里描述的这种计算大小:http: //ehcache.org/documentation/configuration/cache-size#built-in-sizing-computation-and-enforcement
最近我发现从 2.8 版本开始(我使用 2.8.1)还有一个用于此配置的编程 API,您可以使用此库进行设置:https ://github.com/Terracotta-OSS/ ehcache-sizeofengine
有一个针对 Groovy 的这种大小的引擎的实现,它应该解决元类遍历。我已经尝试过了,恕我直言,它不起作用 - 它的核心是这个过滤器:
public void configure(final Filter filter) {
filter.ignoreInstancesOf(groovy.lang.MetaClass.class, false);
}
我认为问题在于 groovy 对象中的 metaClass 字段不是 MetaClass 的实例 - 它在日志中也可见。
所以在这么长的描述之后提出一个问题:
有人遇到同样的问题并以某种方式解决了吗?