efcore: Memory leak in ServiceProviderCache?

I have an application which has a timer, and every minute it does this:

using (var context = new MyDbContext()) 
{
  // do some work
  context.SaveChanges();
}

Gradually over time the memory usage of the process has been going up, and eventually it crashed with an OutOfMemoryException.

So I ran it again, took a memory dump, and investigated where the memory was going:

image

The ServiceProviderCache seems to gradually be growing with a new ServiceProvider every time it creates a context, and doesn’t seem to get freed on the Dispose.

Steps to reproduce

for (int i = 0; i < 1000; i++)
{
  using (var context = new MyDbContext())
  {
    context.SomeSet.Add(new SomeEntity());
    context.SaveChanges();
  }
}

then check memory usage

Further technical details

EF Core version: 2.0.0 Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Windows 10 IDE: VS 2017

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 5
  • Comments: 21 (6 by maintainers)

Commits related to this issue

Most upvoted comments

@gallivantor It is the creation of a new ILoggerFactory instance for each context instance that is causing the problem. Instead you should have one shared ILoggerFactory, or at least a very small number, shared by all your context instances. I agree that this is pretty unrecoverable–we will discuss what we can do to mitigate the issue.

I am having the same issue as @voroninp on 3.1.13. It seems if I add an entity to my DbContext, that context will never be cleaned up, which sounds a lot like the issue described in #21092. I have a generic add method I am using in my context:

TEntity ICamaContext.Add<TEntity>(TEntity entity) { return this.Set<TEntity>().Add(entity).Entity; }

This is the retention graph from Redgate ANTS Memory Profiler. CamaContext has been disposed; ServiceProviderEngineScope has not.

add-retention

@BabellDev the version was ef core 6.0 not 7.0

Great thanks, yep that seems to have fixed it.

I think as this issue isn’t very discoverable – and is the sort of problem that someone could easily put into Production causing a slow-burning memory leak – it would be good if a way could be found to change this behaviour; or at least update the docs to make clear what causes this problem, and perhaps re-word that warning message to be explicit about the fact that it could be creating a memory leak. For example I think I copied that UseLoggerFactory line from a StackOverflow answer somewhere and if other people are doing the same they could be unwittingly introducing a similar bug.

On a side-note, is it possible to use the DBContext Pooling with other DI frameworks? Using the pooling would also work around this problem, but as far as I can tell it’s tied into the Microsoft.Extensions.DependencyInjection DI framework (services.AddDbContextPool) and I have an existing app which is built around using Unity directly

By the way, good work with EF Core. It’s great to be able to interact with the team here on Github, it gives us much more confidence to use the product knowing that we can get answers easily if problems come up.