C# Entity Framework IQueryable 内存泄漏

标签 c# memory-leaks .net-core entity-framework-core

我们看到内存资源没有被释放:

enter image description here

使用以下代码使用 .NET Core:

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我按预期得到一条直线,谓词内存将无限期地继续上升。

因此,虽然我可以解决问题,但我想了解发生了什么?

编辑:

将行更改为:
public void RunTest() {
    using (var context = new EasyMwsContext()) {
        var result = context.FeedSubmissionEntries.ToList();
    }
}

给出图形:
enter image description here

所以我也不相信这是由于客户端评估造成的?

编辑2:

使用 EF 核心 2.1.4

和对象堆:
enter image description here

编辑3:

添加了保留图,似乎是 EF Core 的问题?

enter image description here

最佳答案

我怀疑罪魁祸首不是内存泄漏,而是对 EF Core 的一个相当不幸的补充,Client Evaluation .与 LINQ-to-SQL 一样,当遇到无法转换为 SQL 的 lambda/函数时,EF Core 将创建一个更简单的查询,该查询读取更多数据并在客户端评估该函数。

在您的情况下,EF Core 不知道是什么 TestPredicate所以它会读取内存中的每条记录,然后尝试过滤数据。

顺便说一句 that's what happened当 SO 于 2018 年 10 月 4 日上周四转移到 EF Core 时。查询返回的不是几十行,而是...... 5200 万行:

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));
}

更新

找出泄漏的快速方法是在“诊断”窗口中拍摄两个内存快照并检查创建了哪些新对象以及它们使用了多少内存。客户端评估中很可能存在错误。

关于C# Entity Framework IQueryable 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52735827/

相关文章:

linux - 如何在 Debian Jessie 中安装 dotnet core sdk

c# - 使用 .NET Core 2 的 Azure WebJobs 失败并显示 "Invalid storage account"

c# - 在代码块之后附加方括号

c# - 在 C# 中比较数组

c# - Windows 10 iot (Raspberry PI3 - ARM) 上的 .net 核心安装

C 数组内存泄漏

c# - 具有回调的委托(delegate)的内存泄漏

c# - 创建使用线程的静态类的最佳方法是什么?

javascript - Telerik RadListBox 项目列表如何隐藏字符长度并显示工具提示?

c++ - 在 C++ Builder XE4 中搜索内存泄漏