我们看到内存资源没有释放:
使用.NET Core使用以下代码:
Auto Layout
如果我删除测试谓词class Program
{
static void Main(string[] args)
{
while (true) {
var testRunner = new TestRunner();
testRunner.RunTest();
}
}
}
public class TestRunner {
public void RunTest() {
using (var context = new EasyMwsContext()) {
var result = context.FeedSubmissionEntries.Where(fse => TestPredicate(fse)).ToList();
}
}
public bool TestPredicate(FeedSubmissionEntry e) {
return e.AmazonRegion == AmazonRegion.Europe && e.MerchantId == "1234";
}
}
,则会得到一条直线,如预期那样,有了该谓词,内存将无限期地继续增长。
因此,在我可以解决问题的同时,我想了解发生了什么事?
编辑:
将行更改为:
.Where
所以我也不认为这是由于客户端评估造成的吗?
编辑2:
使用EF Core 2.1.4
编辑3:
添加了保留图,似乎与EF Core有关?
答案 0 :(得分:2)
我怀疑罪魁祸首不是内存泄漏,而是EF Core Client Evaluation的不幸添加。与LINQ-to-SQL一样,当遇到无法转换为SQL的lambda /函数时,EF Core将创建一个更简单的查询,该查询读取更多数据并在客户端上评估该函数。 / p>
在您的情况下,EF Core无法知道TestPredicate
是什么,因此它将读取内存中的每个记录,然后尝试过滤数据。
顺便说一句that's what happened,于SO于2018年10月4日星期四移至EF Core。该查询未返回几十行,而是返回了... 52百万行:
var answers = db.Posts
.Where(p => grp.Select(g=>g.PostId).Contains(p.Id))
...
.ToList();
客户端评估是可选的,但默认情况下处于启用状态。每次执行客户端评估时,EF Core都会记录一条警告,但是如果您没有配置EF Core日志记录,这将无济于事。
安全的解决方案是禁用客户端评估,如文档的Optional behavior: throw an exception for client evaluation部分所示,可以在每种上下文的OnConfiguring
方法中使用,也可以在Startup中全局使用。 cs配置:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(...)
.ConfigureWarnings(warnings =>
warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}
更新
找出泄漏的快速方法是在“诊断”窗口中拍摄两个内存快照,并检查创建了哪些新对象以及它们使用了多少内存。客户评估中很可能存在错误。
答案 1 :(得分:2)
我最终遇到了同样的问题。一旦知道了问题所在,便可以在EntityFrameworkCore存储库中here找到错误报告。
简短的摘要是,当您将实例方法包含在IQueryable中时,它将被缓存,并且即使在处理完上下文后也不会释放这些方法。
目前,在解决该问题上似乎还没有取得太大进展。我会一直关注它,但就目前而言,我认为避免内存泄漏的最佳选择是: