I'm experiencing a memory leak when using an EF Core 3.1.5 (after migration from 2.2) with Autofac 5.2.0. My scenario is that on the home page I load some list of products and each reload of a page increase the amount of memory used by 5-10mb, memory increase endlessly. It never goes down. I suspect that my registration is wrong(?) or this is because of tracking behavior in EF Core(?). I try to Register my MyDbContext
as follows:
public class DbContextModule<TContext> : Module
where TContext : DbContext
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder
.RegisterType<TContext>()
.WithParameter("options", DbContextOptionsFactory.Get<TContext>())
.InstancePerLifetimeScope();
}
}
public class DbContextOptionsFactory
{
public static DbContextOptions<TContext> Get<TContext>() where TContext : DbContext
{
var confSql = "fake";
var builder = new DbContextOptionsBuilder<TContext>();
DbContextConfigurer.Configure<TContext>(builder, confSql);
return builder.Options;
}
}
public class DbContextConfigurer
{
public static void Configure<TContext>(DbContextOptionsBuilder<TContext> builder, string connectionString) where TContext : DbContext
{
builder.UseSqlServer(connectionString, sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(3),
errorNumbersToAdd: null);
});
}
}
and in a startup file:
public void ConfigureContainer(ContainerBuilder builder)
{
...
builder.RegisterModule<DbContextModule<MyDbContext>>();
...
}
I try to add AsSelf
or ExternallyOwned
but nothing changed.
I also try to register DbContext via Microsoft DI but nothing changed.
Try to use AddDbContextPool
on ServiceCollection
but still without success.
Above problems don't occur when EF Core 2.2 was used.
After some investigation via DotMemory, I saw that I have some big peak of memory usage via ServiceProviderCache. When I try to google ServiceProviderCache EF Core
I found following link.
In my situation, the problem was that I enable the console logging locally to easier spot problems with ef core after migration. The DbContext looks like this:
private readonly ILoggerFactory _loggerFactory;
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
_loggerFactory = LoggerFactory.Create(b => b.AddConsole());
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
if (``it is a local run``)
{
optionsBuilder
.UseLoggerFactory(_loggerFactory)
.EnableSensitiveDataLogging();
}
}
the problematic lines were:
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
_loggerFactory = LoggerFactory.Create(b => b.AddConsole());
}
Based on the answer on GitHub, the logger was created each time the DbContext was created and it wasn't destroyed after that. The solution would be to have a static logger. So I refactor it as follows:
Create ConsoleLogger:
public class ConsoleLogger
{
public readonly ILoggerFactory Instance;
public ConsoleLogger()
{
Instance = Microsoft.Extensions.Logging.LoggerFactory.Create(x => x.AddConsole());
}
}
Register it as a singleton:
...
builder.RegisterType<ConsoleLogger>().AsSelf().SingleInstance();
...
and use it in DbContext like that:
public MyContext(DbContextOptions<MyContext> options, ConsoleLogger consoleLogger)
: base(options) =>
_consoleLogger = consoleLogger;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
if (``it is a local run``)
{
optionsBuilder
.UseLoggerFactory(_consoleLogger.Instance)
.EnableSensitiveDataLogging();
}
}
Thanks to above the memory profiling chart goes from this:
to this:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With