Understanding ehcache and how it works with Play Framework 2.X

1.7k Views Asked by At

We added some choice Cache.getOrElse() statements in our Play 2.2.2 application to store some intermediate products of some rather CPU intensive calculations. Seemed like an easy win! Several of these are rather complex case classes and we noticed that after implementing this we observed two things (a) the memory usage of the JVM goes up substantially (b) we get a bunch of warnings like the following:

 [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.

My initial thinking was that because we are storing these complex classes, that the Cache was sucking in other parts of the object that were required to "fully reconstitute" the object once returned out of the cache. So we created some more simple objects - stripping companion objects, and re-typing any fields in the classes that are not Strings or Ints. But even really simple maps of strings seem to be storing a lot of objects (and therefore I presume a lot of memory used) in the Cache.

An example that stores a map of stringsfrom a redis object:

val value = Cache.getOrElse[Map[String,String]]("Cache:PicturesForFolios", expiration = 840000){
      client.hgetAll("Bookmarks:Photos")
}

This map of redis results we are storing has precisely 256 key -> values and the jedis library returns this as a Map[String,String]. So why would this result in that warning of > 100000 objects being calculated for the cache? Performance-wise this is a huge problem because the calculation of the cache size takes a long time and I'm not sure setting the cache to ignore calculation is a wise choice when ehcache is being used extensively!

What am I not getting about ehcache and how this works? Do I need to do my own serialization of any object I want to put in the cache so that everything is forced to a single key -> value???

1

There are 1 best solutions below

5
On

The warning you are seeing tells you that you're sizing an entry (i.e. the one or two object graphs that the Key & Value represent) which holds more than 100k references. Generally it means you are caching more than you'd expect, as this is a very big object graph. In this case, probably it is related to what the client returns there... If it isn't that, I can only think of how Play uses Ehcache, but I know nothing about that. You'd need to investigate what really makes it in the cache.

Obviously you could not use ARC to size your caches (i.e. use count based sizing), but you probably would only hiding the problem, the cache would still consume much memory. That would lower the latency of puts though, as Ehcache wouldn't try to size your entries anymore.

Lastly, this hasn't anything to do with serialization, as the sizing is about object graphs on the java heap.