EntityFramework Core依赖注入上下文方式不同造成内存泄漏了解一下?
前言
这个问题从未遇见过,是一位前辈问我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依赖注入上下文方式不同造成内存泄漏了解一下?的更多相关文章
- 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平台下, ...
- .net core options 依赖注入的方式
options 依赖注入的方式 public class JwtSettingsOptions { public const string JwtSettings = "JwtSetting ...
- [译]ASP.NET Core依赖注入深入讨论
原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...
- ASP.NET Core依赖注入——依赖注入最佳实践
在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...
- Spring(八):Spring配置Bean(一)BeanFactory&ApplicationContext概述、依赖注入的方式、注入属性值细节
在Spring的IOC容器里配置Bean 配置Bean形式:基于xml文件方式.基于注解的方式 在xml文件中通过bean节点配置bean: <?xml version="1.0&qu ...
- 在WPF中使用依赖注入的方式创建视图
在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...
- # ASP.NET Core依赖注入解读&使用Autofac替代实现
标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...
- Spring学习(三)——Spring中的依赖注入的方式
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...
- net core 依赖注入问题
net core 依赖注入问题 最近.net core可以跨平台了,这是一个伟大的事情,为了可以赶上两年以后的跨平台部署大潮,我也加入到了学习之列.今天研究的是依赖注入,但是我发现一个问题,困扰我很久 ...
随机推荐
- FFPLAY的原理(三)
播放声音 现在我们要来播放声音.SDL也为我们准备了输出声音的方法.函数SDL_OpenAudio()本身就是用来打开声音设备的.它使用一个叫做SDL_AudioSpec结构体作为参数,这个结构体中包 ...
- 解决ubuntu unity下gvim菜单消失的问题
#问题描述:在终端下用gvim 指令打开 gvim就不显示菜单.在不启用unity的桌面环境下用终端打开gvim是有菜单的.从程序菜单中打开gvim是显示菜单的.用sudo打开gvim也可以显示菜单, ...
- 分享一下在aspx页面弹框的设置代码
public static class MessageBox { /// <summary> /// 显示消息提示对话框 /// </summary> /// <para ...
- prometheus alert rules文件格式化
1.下载go(version>1.9,否则promtool工具不好使) https://golang.org/doc/install?download=go1.10.2.linux-amd64. ...
- python笔记:#006#程序执行原理
程序执行原理(科普) 目标 计算机中的 三大件 程序执行的原理 程序的作用 01. 计算机中的三大件 计算机中包含有较多的硬件,但是一个程序要运行,有 三个 核心的硬件,分别是: CPU 中央处理器, ...
- Flask入门之Bootstrap介绍使用和Flask-Nav快速导航栏
一.Bootstrap Bootstrap,来自 Twitter,是目前最受欢迎的前端框架. Python中,同样可以使用Bootstrap. 1. 导入Bootstrap库 from flask_b ...
- R语法学习 第十二篇:因子
因子(factor)是R语言中比较特殊的一个类型, 它是一个用于存储类别的类型,因子的行为有时像字符串,有时像整数.因子也是一个向量,每个元素都是字符类型.因子具有因子水平(Levels),用于限制因 ...
- SpringMVC中的拦截器
1. 自定义拦截器 实现HandlerInterceptor接口 拦截器一: package cn.rodge.ssm.interceptor;import javax.servlet.http.Ht ...
- PAT1102: Invert a Binary Tree
1102. Invert a Binary Tree (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...
- Stack编程队列
题目描述:用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 首先定义两个栈 Stack<Integer> stack1 = new Stack<I ...