0

So I'm using web api to expose data services. Initially I created my dbcontext as a static memory, and each time I open up my project under IISExpress, the memory balloons to over 100MB in memory. I understand that it isnt recommended to use static due to the solved answer here:

Entity framework context as static

So I went ahead and converted my application to using regular non-static dbcontext and included a dispose method on my api:

     protected override void Dispose(Boolean disposing)
    {
        if (provider.Context != null)
        {
            provider.Context.Dispose();
            provider = null;
        }
        base.Dispose(disposing);
    }

Now every time I make a call, it goes through this method and disposes. Now, I open the application, still balloons to 100k, and each time I make a call, I watch the memory of my iisexpress process, and it keeps on going up and it's not coming back down after the dispose, it keeps increasing to almost 200MB+.

So static or not, memory explodes whenever I use it.

Initially I thought it was my web api that was causing it, until I removed all my services and just created the EF object in my api (I'm using breezejs, so this code is trivial, the actual implementation is down below, but makes no diff to memory consumption):

private DistributorLocationEntities context = new DistributorLocationEntities();

And bam, 110MB immediately.

Is there any helpful tips and tweaks on how I can release memory when I use it? Should I add garbage collect to my dispose()? Any pitfalls to allocating and deallocating memory rapidly like that? For example, I make calls to the service each time I make a keystroke to accomplish an "autocomplete" feature.

I'm also not certain what will happen if I put this in production, and we have dozens of users accessing the db; I wouldn't want the users to increase the memory to 1 or 2GB and it doesn't get released.

Side note: All my data services for now are searches, so there are no save changes or updates, though there can be later on though. Also, I don't return any linq queries as an array or enumerable, they remain as queryables throughout the service call.

One more thing, I do use breezejs, so I wrap up my context as such:

readonly EFContextProvider<DistributorLocationEntities> provider = new EFContextProvider<DistributorLocationEntities>();

and the tidbits that goes along with this:

Doc for Breeze's EFContextProvider proxycreationenabled = false
ladyloadingenabled = false
idispose is not included

but I still dispose the context anyways, which makes no difference.

Community
  • 1
  • 1
sksallaj
  • 3,872
  • 3
  • 37
  • 58

2 Answers2

2

I don't know what you're doing. I do know that you should not have any static resources of any kind in your Web API controllers (breeze-flavored or not).

I strongly suspect you've violated that rule.

Adding a Dispose method no difference if the object is never disposed ... which it won't be if it is held in a static variable.

I do not believe that Breeze has any role in your problem whatsoever. You've already shown that it doesn't.

I suggest you start from a clean slate, forget Breeze for now, a get a simple Web API controller that creates a DbContext per request. When you've figured that out, proceed to add some Breeze.

Ward
  • 17,793
  • 4
  • 37
  • 53
  • Hi Ward, I figured out why EF blows up, thanks for your response. I gave this a good read: http://msdn.microsoft.com/en-us/data/hh949853.aspx, I turned off automatic caching for certain contexts, and found out that "contains" degrades EF performance (but is fixed in EF6). The performance hit wasnt from web api or the breeze controller. Thanks for the input as always :) – sksallaj Mar 17 '14 at 14:49
2

As mentioned in Ward's comment, statics are a big no-no, so I spent time on moving my EF objects out of static. Dispose method didn't really help either.

I gave this article a good read:

http://msdn.microsoft.com/en-us/data/hh949853.aspx

There are quite a few performance options EF provides (that doesn't come out of the box). So here are a few things I've done:

  • Added pre-generated views to EF: T4 templates for generating views for EF4/EF5. The nice thing about this is that it abstracts away from the DB and pre-generates the view to decrease model load time
  • Next, I read this post on Contains in EF: Why does the Contains() operator degrade Entity Framework's performance so dramatically?. Apparently I saw an an attractive answer of converting my IEnumerable.Contains into a HashSet.Contains. This boosted my performance considerably.
  • Finally, reading the microsoft article, I realized there is a "AsNoTracking()" that you can hook up to the DBContext, this turns of automatic caching for that specific context in linq. So you can do something like this

    var query = (from t in db.Context.Table1.AsNoTracking() select new { ... }

Something I didn't have to worry about was compiling queries in EF5, since it does it for you automatically, so you don't have to add CompileQuery.Compile(). Also if you're using EF 6 alpha 2, you don't need to worry about Contains or pre-generating views, since this is fixed in that version.

So when I start up my EF, this is a "cold" query execution, my memory goes high, but after recycling IIS, memory is cut in half and uses "warm" query execution. So that explains a lot!

Community
  • 1
  • 1
sksallaj
  • 3,872
  • 3
  • 37
  • 58