Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak when using a shared CancellationTokenSource #30534

Closed
QianMoXi opened this issue Mar 20, 2023 · 3 comments
Closed

Memory leak when using a shared CancellationTokenSource #30534

QianMoXi opened this issue Mar 20, 2023 · 3 comments

Comments

@QianMoXi
Copy link

Ask a question

use a shared cancellationTokenSource, memory usage is getting too high to be freed:
image

use CancellationToken.None:
image

Example

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

internal class Program
{
    private static IServiceProvider _serviceProvider = CreateServiceProvider();

    public static async Task Main(string[] args)
    {
        //If you use a Shared CancellationTokenSource, will cause the memory cannot be released
        var shareTokenSource = new CancellationTokenSource();
        await InitDbAsync(shareTokenSource.Token);
        await WriteToDbAsync(shareTokenSource.Token);

        //If you use CancellationToken.None, no such problem occurs
        await InitDbAsync(CancellationToken.None);
        await WriteToDbAsync(CancellationToken.None);
    }

    public static async Task InitDbAsync(CancellationToken cancellationToken)
    {
        await using var context = await _serviceProvider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContextAsync(cancellationToken);
        await context.Database.EnsureDeletedAsync(cancellationToken);
        await context.Database.EnsureCreatedAsync(cancellationToken);
    }

    public static async Task WriteToDbAsync(CancellationToken cancellationToken)
    {
        for (var i = 0; i < 1000; i++)
        {
            await using var context = await _serviceProvider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContextAsync(cancellationToken);

            var data = Enumerable.Range(0, 1000).Select(_ => new TableA()).ToList();

            await context.AddRangeAsync(data, cancellationToken);

            await context.SaveChangesAsync(cancellationToken);

            Console.WriteLine($"{i} TotalMemory: {GC.GetTotalMemory(true)}");
        }

    }

    public static IServiceProvider CreateServiceProvider()
    {
        var services = new ServiceCollection();
        services.AddDbContextFactory<MyDbContext>(builder =>
        {
            builder.UseSqlServer("Data Source=.;Initial Catalog=DbMemoryTest;MultipleActiveResultSets=True;Encrypt=False;Integrated Security=SSPI", b =>
            {
                b.EnableRetryOnFailure();
            });
        });

        return services.BuildServiceProvider();
    }

    public class MyDbContext : DbContext
    {
        public DbSet<TableA> TableAs { get; set; }
        public MyDbContext(DbContextOptions options) : base(options)
        {
        }
    }

    public class TableA
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        public Guid Property1 { get; set; } = Guid.NewGuid();
        public Guid Property2 { get; set; } = Guid.NewGuid();
        public Guid Property3 { get; set; } = Guid.NewGuid();
        public Guid Property4 { get; set; } = Guid.NewGuid();
    }
}

Possible reasons

Data is always in ExecutionContext
image

Include provider and version information

EF Core version: 7.0.4
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 7.0
Operating system: Windows 11 22H2
IDE: Visual Studio 2022 17.5.2

@ajcvickers
Copy link
Contributor

This only repros with Microsoft.Data.SqlClient 5.0.1, not on 5.1.0. Likely dotnet/SqlClient#1810

@QianMoXi Explicitly reference Microsoft.Data.SqlClient 5.1.0. For example:

<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.0" />

@QianMoXi
Copy link
Author

@ajcvickers Thanks, it works fine

@roji roji closed this as not planned Won't fix, can't repro, duplicate, stale Mar 24, 2023
@roji
Copy link
Member

roji commented Mar 24, 2023

Duplicate of dotnet/SqlClient#1810

@roji roji marked this as a duplicate of dotnet/SqlClient#1810 Mar 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants