使用 Autofac 和 EF Core 3.1 的内存泄漏(从 2.2 迁移后)

MNi*_*Nie 5 c# entity-framework-core .net-core asp.net-core ef-core-3.1

将 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);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

并在启动文件中:

public void ConfigureContainer(ContainerBuilder builder)
{
    ...
    builder.RegisterModule<DbContextModule<MyDbContext>>();
    ...
}
Run Code Online (Sandbox Code Playgroud)

我尝试添加AsSelfExternallyOwned但没有任何改变。我也尝试通过 Microsoft DI 注册 DbContext,但没有任何改变。尝试使用AddDbContextPoolonServiceCollection但仍然没有成功。

使用 EF Core 2.2 时不会出现上述问题。

MNi*_*Nie 8

在通过 DotMemory 进行一些调查后,我发现通过 ServiceProviderCache 出现了一些内存使用高峰。当我尝试使用谷歌搜索时,ServiceProviderCache EF Core我发现了以下链接

在我的情况下,问题是我在本地启用控制台日志记录,以便在迁移后更容易地发现 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

有问题的线路是:

public MyContext(DbContextOptions<MyContext> options)
            : base(options)
{
    _loggerFactory = LoggerFactory.Create(b => b.AddConsole());
}
Run Code Online (Sandbox Code Playgroud)

根据 GitHub 上的答案,每次创建 DbContext 时都会创建记录器,此后不会销毁它。解决方案是使用静态记录器。所以我重构如下:

创建控制台记录器:

public class ConsoleLogger
{
    public readonly ILoggerFactory Instance;

    public ConsoleLogger()
    {
        Instance = Microsoft.Extensions.Logging.LoggerFactory.Create(x => x.AddConsole());
    }
}
Run Code Online (Sandbox Code Playgroud)

将其注册为单例:

...
builder.RegisterType<ConsoleLogger>().AsSelf().SingleInstance();
...
Run Code Online (Sandbox Code Playgroud)

并在 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

由于上面的内存分析图表来自于此: 在此处输入图片说明 在此处输入图片说明 对此: 在此处输入图片说明