Kel*_*son 3 .net entity-framework entity-framework-core asp.net-core
这涉及 Microsoft.EntityFrameworkCore.SqlServer,特别是版本 2.1.14
我在服务层中使用 EF,该服务的 API 之一用于批量操作。所有上下文相关的代码都使用构造函数注入。连接字符串确实启用了 MARS。我像这样注册我的数据库上下文:
services.AddDbContext<ServiceAvailabilityContext>(options => options.UseSqlServer(saConnection));
Run Code Online (Sandbox Code Playgroud)
我已确保所有调用代码都作为作用域任务执行运行。我有一个批处理进程,它同时执行 50 个任务操作,总共 500 个,并将尝试定期运行 500 个。然而,我注意到随着时间的推移,该服务的堆大小内存消耗不断增加。我已经在我的开发机器上运行批处理器和服务,并尝试运行服务运行时构建,使其增长到三台。
每个服务命令或查询都在 IMediatR IRequestHandler 中运行,为了确保它们作为 Scoped 被调用,我添加了管道行为,如下所示:
var response = await Task.Run(async () =>
{
using (var scope = _serviceScopeFactory.CreateScope())
{
return await next();
}
});
Run Code Online (Sandbox Code Playgroud)
调用堆栈基本上是控制器 -> MediatR 请求处理程序(注入的上下文构造函数) -> 操作。
看起来 EF 只是将所有类型的集合保留在内存中,并且出于某种原因没有释放它们,即使原始上下文已超出范围,并且所有其他引用也已超出范围。我不会返回 IQueryables,每次检索数据时,我都会立即执行 .ToList() 或 .FirstorDefault() 来完成语句。我什至从未在模型中返回实体对象本身,而是将它们类型转换为 UI 友好的对象。我还尝试过调用一个方法来命中断点,并手动调用 GC.Collect() ,但没有释放任何内存!
我的主要问题是......为什么?我缺少什么?
事实证明,即使 DbContext 与 DI 范围一起使用,幕后的 ChangeTracker 仍保留对象 HashSets。当不修改对象或分离调用 SaveChanges() 后所做更改的对象时,我必须更改检索语句以使用 AsNoTracking(),从而解决了内存问题。
一种更简单的方法可能是将您的上下文注册为瞬态,这样您就不必陷入这样的困境。