我们在 Play 2.2.2 应用程序中添加了一些选择 Cache.getOrElse() 语句来存储一些 CPU 密集型计算的一些中间产品。看起来很容易获胜!其中一些是相当复杂的案例类,我们注意到在实现它之后我们观察到两件事(a)JVM的内存使用量大幅上升(b)我们收到一堆警告,如下所示:
[warn] 20:01:57 net.sf.ehcache.pool.sizeof.SizeOf: The configured limit of 100,000 object references was reached while attempting to calculate the size of the object graph.
This can be avoided by adding stop points with @IgnoreSizeOf annotations. Since the CacheManger or Cache <sizeOfPolicy> elements maxDepthExceededBehavior is set to "abort", the sizing operation has stopped and the reported cache size is not accurate.
If performance degradation is NOT an issue at the configured limit, raise the limit value using the CacheManager or Cache <sizeOfPolicy> elements maxDepth attribute.
For more information, see the Ehcache configuration documentation.
我最初的想法是,因为我们正在存储这些复杂的类,所以缓存正在吸收对象的其他部分,一旦从缓存中返回,就需要“完全重构”对象。所以我们创建了一些更简单的对象——剥离伴随对象,并重新键入类中不是字符串或整数的任何字段。但即使是非常简单的字符串映射似乎也在缓存中存储了很多对象(因此我假设使用了很多内存)。
存储来自 redis 对象的字符串映射的示例:
val value = Cache.getOrElse[Map[String,String]]("Cache:PicturesForFolios", expiration = 840000){
client.hgetAll("Bookmarks:Photos")
}
我们存储的这个 redis 结果映射正好有 256 个键 -> 值,jedis 库将其作为 Map[String,String] 返回。那么为什么这会导致为缓存计算超过 100000 个对象的警告呢?就性能而言,这是一个巨大的问题,因为缓存大小的计算需要很长时间,而且当 ehcache 被广泛使用时,我不确定将缓存设置为忽略计算是一个明智的选择!
我对 ehcache 没有什么了解以及它是如何工作的?我是否需要对要放入缓存中的任何对象进行自己的序列化,以便将所有内容强制为单个键-> 值???