前言

这个问题从未遇见过,是一位前辈问我EF Core内存泄漏问题时我才去深入探讨这个问题,刚开始我比较惊讶,居然还有这种问题,然后就有了本文,直接拿前辈的示例代码并稍加修改成就了此文,希望对在自学EF Core过程中的童鞋能有些许帮助。

EntityFramework Core内存泄漏回顾

接下来我将用简单示例代码来还原整个造成EntityFramework Core内存泄漏的过程,同时在这个过程中您也可思考一下其中的原因和最终的结果是否一致。

    public class TestA
{
public long Id { get; set; }
public string Name { get; set; }
}
    public class EFCoreDbContext : DbContext
{
public EFCoreDbContext(DbContextOptions options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;");
base.OnConfiguring(optionsBuilder);
} public DbSet<TestA> TestA { get; set; }
}
    public class TestUserCase
{
public void InvokeMethod(IServiceProvider serviceProvider)
{
EFCoreDbContext _context = null; if (_context == null)
{
_context = serviceProvider.GetRequiredService<EFCoreDbContext>();
} for (var i = ; i < ; i++)
{
var testA = _context.TestA.FirstOrDefault();
Console.WriteLine(i);
}
}
}

如上是整个示例代码,重头戏来了,接下来我们在控制台中来通过依赖注入上下文,并获取注入容器中的上下文并调用上述TestUserCase类中的方法,如下:

            var services = new ServiceCollection();

            services.AddDbContext<EFCoreDbContext>(options => options.UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;"));

            var serviceProvider = services.BuildServiceProvider();

            for (int i = ; i < ; i++)
{
var test = new TestUserCase();
test.InvokeMethod(serviceProvider);
}

通过上述测试内存基本在15兆左右,当然根据机器配置不同最终得到的结果有所差异,但是内存基本没有什么大的波动,接下来我们来改造上述代码。上述我们将serviceProvider通过方法传递到TestUserCase中的InvokeMethod方法中,为了简便我们将获取到的serviceProvider改造成静态的,如下:

    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;
}
}
    public class TestUserCase
{
public void InvokeMethod()
{
IServiceScope _serviceScope = null;
EFCoreDbContext _context = null;
if (_context == null)
{
_serviceScope = ServiceLocator.Instance.GetRequiredService<IServiceScopeFactory>().CreateScope();
_context = _serviceScope.ServiceProvider.GetRequiredService<EFCoreDbContext>();
} for (var i = ; i < ; i++)
{
var testA = _context.TestA.FirstOrDefault();
Console.WriteLine(i);
}
}
}
            var services = new ServiceCollection();

            services.AddDbContext<EFCoreDbContext>(options => options.UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;"));

            ServiceLocator.Init(services);

            for (int i = ; i < ; i++)
{
var test = new TestUserCase();
test.InvokeMethod();
}

如上我们通过ServiceLocator类来构建serviceProvider,并将返回serviceProvider赋值给静态变量,然后在我们调用的方法中直接获取容器中的上下文,这样就免去了传递的麻烦。

经过我们上述改造后最终运行内存达到了比较可怕的三百多兆,看来上下文压根就没进行GC,那我是不是改造成如下就可以了呢?

            var scopeFactory = ServiceLocator.Instance.GetRequiredService<IServiceScopeFactory>();

            using (var scope = scopeFactory.CreateScope())
using (var context = scope.ServiceProvider.GetRequiredService<EFCoreDbContext>())
{
for (var i = ; i < ; i++)
{
var testA = context.TestA.FirstOrDefault();
Console.WriteLine(i);
}
}

原以为是上下文没有及时得到释放而导致内存激增,但是看到上述结果依然一样没有任何改变,问题是不是到此就结束了呢?下面我们改变注入上下文的方式看看,如下:

            var services = new ServiceCollection();

            var options = new DbContextOptionsBuilder<EFCoreDbContext>()
.UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;")
.Options;
services.AddScoped(s => new EFCoreDbContext(options));

当我们改变了注入上下文方式后发现此时不会造成内存泄漏,也就是说上下文得到了GC,无论是我是否是手动释放上下文即通过Using包括或者不包括都不会出现内存泄漏问题。通过注入方式不同得到的结果截然不同,但是在我们的理解中通过AddDbContext注入上下文中的第二个参数是默认为Scope,那和我们通过AddScoped注入上下文应该是一样对不对,那为何结果又不同呢?岂不是冲突了吗?在Web不会出现这样的问题,未深入研究,我猜测其原因可能如下:

通过AddDbContext注入上下文只适用于Web应用程序即只对Web应用程序有效而对控制台程序可能无效,同时在Web应用程序中AddDbContext注入上下文和AddScoped注入上下文一致,而对于控制台程序存在不一致问题。一言以蔽之,在Web和Console中通过AddDbContext注入上下文可能存在处理机制不同。

总结

不知如上浅薄分析是否有漏洞或者说代码有错误的地方,期待看到本文的您能有更深入的见解可留下您的评论,如果结果是这样不建议在控制台中使用AddDbContext方法注入上下文。

EntityFramework Core依赖注入上下文方式不同造成内存泄漏了解一下?的更多相关文章

  1. Webservice WCF WebApi 前端数据可视化 前端数据可视化 C# asp.net PhoneGap html5 C# Where 网站分布式开发简介 EntityFramework Core依赖注入上下文方式不同造成内存泄漏了解一下? SQL Server之深入理解STUFF 你必须知道的EntityFramework 6.x和EntityFramework Cor

    Webservice WCF WebApi   注明:改编加组合 在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web API.在.net平台下, ...

  2. .net core options 依赖注入的方式

    options 依赖注入的方式 public class JwtSettingsOptions { public const string JwtSettings = "JwtSetting ...

  3. [译]ASP.NET Core依赖注入深入讨论

    原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...

  4. ASP.NET Core依赖注入——依赖注入最佳实践

    在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...

  5. Spring(八):Spring配置Bean(一)BeanFactory&ApplicationContext概述、依赖注入的方式、注入属性值细节

    在Spring的IOC容器里配置Bean 配置Bean形式:基于xml文件方式.基于注解的方式 在xml文件中通过bean节点配置bean: <?xml version="1.0&qu ...

  6. 在WPF中使用依赖注入的方式创建视图

    在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...

  7. # ASP.NET Core依赖注入解读&使用Autofac替代实现

    标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...

  8. Spring学习(三)——Spring中的依赖注入的方式

    [前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...

  9. net core 依赖注入问题

    net core 依赖注入问题 最近.net core可以跨平台了,这是一个伟大的事情,为了可以赶上两年以后的跨平台部署大潮,我也加入到了学习之列.今天研究的是依赖注入,但是我发现一个问题,困扰我很久 ...

随机推荐

  1. 用Socket编写的聊天小程序

    Socket是什么? 是套接字,除此之外我也不太清楚,先略过 直接上实例,首先服务端: ; //自定义端口号 private string ServerUser = "Tracy" ...

  2. CentOS6.5 64位下安装部署Ansible

    这里使用的软件包为一下版本 Python-2.7.12.tgz pip-9.0.1.tar.gz ansible-2.2.0.0.tar.gz 其他依赖包使用pip方式安装 方便说明做以下设定: 控制 ...

  3. 关于Django Web应用架构设计开发的几个问题

    1.关于分层,做过传统JEE应用的同学肯定知道JEE应用会分很多个设计层.根据传统Web应用架构设计一般从上到下分这么几个层(太懒了,不画图了):Web前端层.Web后端交互层.业务层.基础数据设施层 ...

  4. Postgresql 启动could not create listen socket for "localhost"错误的解决

    新装的postgresql在第一次启动时可能会遇到错误,日志中的记录是: could not create listen socket for "localhost" 到/etc/ ...

  5. [ Java面试题 ]基础篇之一

    1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致. 2.Java有 ...

  6. Dubbo配置引发的一个问题--- Duplicate spring bean id

    1.原因 因项目业务需要,要调用RPC框架,项目原本已经依赖了很多RPC接口需要启动时加载,所以准备做成启动时不预加载. 就是在配置的时候加上check=false. 官方文档解释的作用,就是Dubb ...

  7. centos/linux 禁止root用户远程登录

    注意:在禁止root等前要建立一个用户用来远程登录,否则退出后无法通过远程登录服务器. 编辑 /etc/ssh/sshd_config 文件 更改参数 PermitRootLogin yes 为 Pe ...

  8. Xapth 添加注释头

    private static void updateMybatisXml(String url, String username, String password) { DocumentBuilder ...

  9. CentOS 7.4 MySQL 5.7.20主从环境搭建(M-S)

    MySQL主从原理: 一,master记录二进制日志,在每个事务更新数据完成之前,master在二进制日志中记录这些改变.mysql将事务写入二进制日志,即使事务中的语句都是交叉执行的.在事件写入二进 ...

  10. .NET Core使用微软官方类库实现汉字转拼音

    一.NuGet包 拼音:Install-Package SimplifiedChinesePinYinConversion 简体-繁体互转:Install-Package TraditionalChi ...