簡體   English   中英

多線程控制台應用程序中的EF核心內存泄漏

[英]EF core Memory leak in multithreaded console application

我創建了一個小型控制台應用程序,在其中模擬我在 Azure 服務總線消息傳遞應用程序中使用 EF 核心的內存泄漏問題。

設置如下:

我從 MyContext 中的 DbContext 繼承

public class MyContext : DbContext
{
    private readonly Assembly configurationAssembly;

    public MyContext(Assembly configurationAssembly, DbContextOptions dbContextOptions) : base(dbContextOptions)
    {
        this.configurationAssembly = configurationAssembly;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfigurationsFromAssembly(this.configurationAssembly);
    }
}

我有一個 POCO 課程:

public class Job
{
    public int Id { get; set; }
    public string Applicationcode { get; set; }
}

和一個 EntityTypeConfiguration:

public class JobConfig : IEntityTypeConfiguration<Job>
{
    public void Configure(EntityTypeBuilder<Job> builder)
    {
        builder.ToTable("Job_OP");
    }
}

MyContext 在 OnModelCreating 覆蓋 (ApplyConfigurationFromAssembly) 中使用此配置

最后在程序中我有以下代碼:

class Program
{
    private static IContainer container;
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder(); //Autofac dependency injection

        var dbContextOptionsBuilder = new DbContextOptionsBuilder().UseSqlServer("Data Source=localhost;Initial Catalog=TestEFThreads;Integrated Security=True");

        builder.Register(ctx => new MyContext(
            Assembly.Load("TestEFThreads"),
            dbContextOptionsBuilder.Options));
        //I tried to use different lifetime scopes here, but EF doesn't like using the same dbContext concurrently in different threads.
        //Currently each resolve instantiates a new MyContext

        container = builder.Build();

        var input = ShowMenu();
        var nrOfSimulatedMessages = 0;
        while (!string.Equals(input, "q", StringComparison.OrdinalIgnoreCase))
        {
            try
            {
                nrOfSimulatedMessages = Convert.ToInt32(input);
                PerformSimulation(maxThreads: 10, nrOfSimulatedMessages);
            }
            catch (Exception e)
            {
                Console.WriteLine($"Incorrect input or exception, {e}");
            }
            input = ShowMenu().ToLower();
        }
    }

    static string ShowMenu()
    {
        Console.WriteLine("Enter number of simulated messages or q to quit");
        return Console.ReadLine();
    }

    private static void PerformSimulation(int maxThreads, int nrOfSimulatedMessages)
    {
        var messageCount = 0;

        var tasks = new Task[maxThreads];

        while (messageCount < nrOfSimulatedMessages)
        {
            for (int i = 0; i < maxThreads && messageCount < nrOfSimulatedMessages; i++)
            {
                Console.WriteLine($"Creating thread {i} for message {messageCount}");
                tasks[i] = new Task(StartProcessing);
                tasks[i].Start();
                messageCount++;
            }
            Console.WriteLine("Waiting for all threads to finish");
            Task.WaitAll(tasks.Where(a=>a !=null).ToArray());
        }
    }

    private static void StartProcessing()
    {
        using (var lifeTime = container.BeginLifetimeScope()) //does not help
        {
            var myContext = container.Resolve<MyContext>();
            var job = myContext.Set<Job>().SingleOrDefault(a => a.Id == 1);
            Console.WriteLine($"Found job with applicationCode {job.Applicationcode}");
            myContext.Dispose(); //memory leak even with dispose
        }
    }
}

因此,此應用程序從數據庫中進行簡單的讀取,並執行指定的次數,每次都在一個單獨的線程中。

當我運行它大約 50000 條“消息”時,內存不斷增加,如診斷中所見。 它似乎沒有被垃圾收集。

診斷

有沒有人知道如何解決這個內存泄漏?

更新:它似乎與 Autofac 依賴注入有關。 如果我只是使用新的 MyContext iso 解決它的內存使用情況就可以了。

    private static void StartProcessing()
    {
        var myContext = new MyContext(Assembly.Load("TestEFThreads"), dbContextOptionsBuilder.Options);

        var job = myContext.Set<Job>().SingleOrDefault(a => a.Id == 1);
        Console.WriteLine($"Found job with applicationCode {job.Applicationcode}");
    }

但是,我確實需要使用依賴注入。

使用 ExternallyOwned 似乎可以解決問題。

    builder.Register(ctx => new MyContext(
        Assembly.Load("TestEFThreads"),
        dbContextOptionsBuilder.Options)).ExternallyOwned();

正常內存消耗

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM