Утечка памяти с использованием Autofa c с EF Core 3.1 (после миграции с 2.2) - PullRequest
1 голос
/ 16 июня 2020

У меня утечка памяти при использовании EF Core 3.1.5 (после миграции с 2.2) с Autofa c 5.2.0. Мой сценарий заключается в том, что на домашней странице я загружаю некоторый список продуктов, и каждая перезагрузка страницы увеличивает объем используемой памяти на 5-10 МБ, память увеличивается бесконечно. Это никогда не выходит из строя. Я подозреваю, что моя регистрация неверна (?) Или это из-за поведения отслеживания в 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, но ничего не изменилось. Я также пытаюсь зарегистрировать DbContext через Microsoft DI, но ничего не изменилось. Попробуйте использовать AddDbContextPool на ServiceCollection, но все равно безуспешно.

При использовании EF Core 2.2 вышеуказанных проблем не возникает.

1 Ответ

3 голосов
/ 17 июня 2020

После некоторого исследования с помощью DotMemory я увидел, что у меня есть большой пик использования памяти через ServiceProviderCache. Когда я пытаюсь использовать Google ServiceProviderCache EF Core, я обнаружил следующую ссылку .

В моей ситуации проблема заключалась в том, что я включил локальное ведение журнала консоли, чтобы облегчить обнаружение проблем с ядром ef после миграции. 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();
    }
}

проблемные c строки были:

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

На основе ответа на GitHub регистратор создавался каждый раз, когда создавался DbContext и после этого он не был уничтожен. Решением было бы иметь регистратор stati c. Поэтому я реорганизовал его следующим образом:

Создать ConsoleLogger:

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();
    }
}

Благодаря вышесказанному диаграмма профилирования памяти выглядит следующим образом: enter image description here enter image description here до этого: enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...