使用带有 EF Core 3.1 的 Autofac 的内存泄漏(从 2.2 迁移后)
Memory leak using Autofac with EF Core 3.1 (after migration from 2.2)
我在将 EF Core 3.1.5(从 2.2 迁移后)与 Autofac 5.2.0 一起使用时遇到内存泄漏。我的场景是在主页上加载一些产品列表,每次重新加载页面都会增加 5-10mb 的内存使用量,内存会无休止地增加。它永远不会下降。我怀疑我的注册有误(?)或者这是因为 EF Core 中的跟踪行为(?)。我尝试按如下方式注册我的 MyDbContext
:
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);
});
}
}
并在启动文件中:
public void ConfigureContainer(ContainerBuilder builder)
{
...
builder.RegisterModule<DbContextModule<MyDbContext>>();
...
}
我尝试添加 AsSelf
或 ExternallyOwned
但没有任何改变。
我也尝试通过 Microsoft DI 注册 DbContext 但没有任何改变。
尝试在 ServiceCollection
上使用 AddDbContextPool
但仍然没有成功。
使用EF Core 2.2时不会出现以上问题
通过 DotMemory 进行一些调查后,我发现通过 ServiceProviderCache 出现了一些内存使用高峰。当我尝试 google ServiceProviderCache EF Core
时,我发现以下 link.
在我的情况下,问题是我在本地启用了控制台日志记录,以便在迁移后更容易发现 ef core 的问题。 DbContext 看起来像这样:
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();
}
}
有问题的行是:
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
_loggerFactory = LoggerFactory.Create(b => b.AddConsole());
}
根据 GitHub 上的回答,每次创建 DbContext 时都会创建记录器,之后不会被销毁。解决方案是拥有一个静态记录器。所以我重构如下:
创建控制台记录器:
public class ConsoleLogger
{
public readonly ILoggerFactory Instance;
public ConsoleLogger()
{
Instance = Microsoft.Extensions.Logging.LoggerFactory.Create(x => x.AddConsole());
}
}
注册为单例:
...
builder.RegisterType<ConsoleLogger>().AsSelf().SingleInstance();
...
并像这样在 DbContext 中使用它:
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();
}
}
多亏了上面的内存分析图表:
对此:
我在将 EF Core 3.1.5(从 2.2 迁移后)与 Autofac 5.2.0 一起使用时遇到内存泄漏。我的场景是在主页上加载一些产品列表,每次重新加载页面都会增加 5-10mb 的内存使用量,内存会无休止地增加。它永远不会下降。我怀疑我的注册有误(?)或者这是因为 EF Core 中的跟踪行为(?)。我尝试按如下方式注册我的 MyDbContext
:
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);
});
}
}
并在启动文件中:
public void ConfigureContainer(ContainerBuilder builder)
{
...
builder.RegisterModule<DbContextModule<MyDbContext>>();
...
}
我尝试添加 AsSelf
或 ExternallyOwned
但没有任何改变。
我也尝试通过 Microsoft DI 注册 DbContext 但没有任何改变。
尝试在 ServiceCollection
上使用 AddDbContextPool
但仍然没有成功。
使用EF Core 2.2时不会出现以上问题
通过 DotMemory 进行一些调查后,我发现通过 ServiceProviderCache 出现了一些内存使用高峰。当我尝试 google ServiceProviderCache EF Core
时,我发现以下 link.
在我的情况下,问题是我在本地启用了控制台日志记录,以便在迁移后更容易发现 ef core 的问题。 DbContext 看起来像这样:
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();
}
}
有问题的行是:
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
_loggerFactory = LoggerFactory.Create(b => b.AddConsole());
}
根据 GitHub 上的回答,每次创建 DbContext 时都会创建记录器,之后不会被销毁。解决方案是拥有一个静态记录器。所以我重构如下:
创建控制台记录器:
public class ConsoleLogger
{
public readonly ILoggerFactory Instance;
public ConsoleLogger()
{
Instance = Microsoft.Extensions.Logging.LoggerFactory.Create(x => x.AddConsole());
}
}
注册为单例:
...
builder.RegisterType<ConsoleLogger>().AsSelf().SingleInstance();
...
并像这样在 DbContext 中使用它:
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();
}
}
多亏了上面的内存分析图表: