Microsoft.Extensions.DependencyInjection不同版本导致EF出现内存泄露。

我的代码里将IServiceProvider放入ServiceLocator中遇到的问题。

注:以下所有例子都是Console里的结论,AspNetCore里不管怎么玩都没有问题,有其他帖子测试出在Asp.net Core里也存在问题,具体他怎么一个写法导致的没细研,在目前我自己项目中用到的范围内Web环境一切OK。

方案1:每次获取IServiceProvider 需要_services.BuildServiceProvider(); ;其中private static IServiceCollection _services; 为静态。

public static class ServiceLocator
    {
        private static IServiceCollection _services;

        public static IServiceProvider Instance
        {
            get
            {
                if (_services == null)
                    return null;
                else
                    return _services.BuildServiceProvider();
            }
        }

        public static void Init(IServiceCollection services)
        {
            _services = services;
        }
    }

方案2:每次获取IServiceProvider 直接取IServiceProvider的静态属性; 其中public static IServiceProvider ServiceProvider { get; private set; }为静态。

public static class ServiceLocator
{
    private static IServiceProvider _servicesProvider;

    public static IServiceProvider Instance
    {
        get
        {
          return _servicesProvider;
        }
    }

    public static void Init(IServiceCollection services)
    {
        _servicesProvider = services.BuildServiceProvider();
    }
}         

EF6或dapper项目中使用Microsoft.Extensions.DependencyInjection1.0 时,用方案1正确,用方案2会出现内存泄露。

使用EF Core2.0时(强依赖于Microsoft.Extensions.DependencyInjection2.0),用方案2正确,用方案1会出现内存泄露。

使用EF Core2.0且用方案1时,可以把官方扩展方法AddDbContext替换为以下代码避免出现内存泄露:

var options = new DbContextOptionsBuilder<XXDbContext>().UseSqlServer("connstr").Options;
services.AddScoped(s => new XXDbContext(options));  感谢Jeffcky提供此方法

目前我用EF Core2.0 ,使用了方案2,感觉存个静态的IServiceProvider也更合理。

刨根究底的事,等有空老衲深入研究下。

另:若使用像Orleans的Actor模型这类具有高度隔离性的东东,慎用Scoped级别的DbContext,一个DbContext同时跨多个Actor导致事务失效。

原文地址:https://www.cnblogs.com/wintersoft/p/9100425.html