Tuesday, October 21, 2014

High Sitecore memory consumption

Case

We experienced a problem last week on a number of servers that steadily kept on using up memory.
After inspection it turned out that each and every page request was creating up-to 7 new caches for BlobId's. Since we saw the following in our logs:



As you can see, each of these caches took up 500KB and in our case (since 7 caches were created) this resulted in a 3,5MB of consumed memory on the server for each page request.
Furthermore, it turned out that these caches were not accessed or used at all but only kept on consuming valuable memory.

Find the problem and solution below so you never make the same mistake and don't have to embark on a wild goose-hunt to solve this one.

Okay, how did we fix this and what was causing it !?

First off, our sincerest thanks to the intervention of Sitecore support which helped us pinpoint the problem directly and made for a quick resolve.

Sitecore informed us that the creation of these cache entries is done when a new instance of a Sitecore Database object is created instead of using the Factory that helps provide these.

In other words:         new Database("web"); 

The reason that we had the problem appear so heavily is that the following code:
LanguageCollection configuredLanguages = LanguageManager.GetLanguages(new Database("web"));
 was used in a utility method for handling language information... and of course this method was called a number of times.


Where we should be using any of the below:  
var database = Sitecore.Data.Database.GetDatabase("web");
var database = Sitecore.Configuration.Factory.GetDatabase("web")

Or in the case where you just need the current context database:
var database = Sitecore.Context.Database;

Cool, any pitfalls though ?

Obviously no pitfalls exist here. The only important thing that has to be done is make sure NONE of your projects/code bases are still using the red-highlighted code above.

2 comments:

  1. Flail the developer that wrote that code! :-)

    All Sitecore documentation states clearly to use the GetDatabase function on either the Database or Factory classes. Stackoverflow has many posts regarding this common mistake as well. When you use a constructor you have to know what you're constructing...

    Deep code you'll see that Database.GetDatabase is merely a shortcut to Factory.GetDatabase and that Factory accesses your configuration to initialize the Database object. Furthermore it keeps a cache of those instances so they are only constructed once (preventing the memory leak you're observing).

    ReplyDelete
  2. He is breathing no more :) Actually the main problem was not the main adoption of this approach, rather the fact that it snuck it's way in there somewhere, and finding it was the tricky part.
    The primary developer reaction was one of suprise on the fact that this was even (still) possible :)

    ReplyDelete