【问题标题】:OutOfMemoryException when iterating large dataset迭代大型数据集时出现 OutOfMemoryException
【发布时间】:2017-02-18 21:45:18
【问题描述】:

我有一个大约有 100,000 行的表(而且它会变得更大)。

当我在循环中达到大约 80,000 条记录时,我的代码现在正在抛出 OutOfMemoryException(即使我的系统当时有超过 10gb 的可用空间,看起来 Visual Studio 被限制在 1.5gb 左右)。

该代码旨在遍历所有记录并仅检查某些条件。我取出了实际处理记录的代码,但内存仍然被填满。

using (var db = new PlaceDBContext())
{
    Messages.Output("Total: " + db.Companies.Count());
    int count = 0;
    foreach (var company in db.Companies)
    {

        // I am not actually doing anything here,
        // I took out my code and the memory still fills up
        // CheckMatchConditions(company);

        count++;

        Console.SetCursorPosition(0, Console.CursorTop);
        Console.Write(count.ToString() + "          ");

    }

}

我认为这可能与保持上下文打开有关,因此我将代码重构为一次仅获取 1,000 条记录,并首先将它们全部枚举到一个列表中。这是我想出的:

int count = 0;
int total = 0;
using (var db = new PlaceDBContext())
{
    Messages.Output("Total: " + db.Companies.Count());
    total = db.Companies.Count();
}
while (count < total)
{
    List<Company> toMatch = new List<Company>();
    using (var db = new PlaceDBContext())
    {
        toMatch = db.Companies.Include(x => x.CompaniesHouseRecords).OrderBy(x => x.ID).Skip(count).Take(1000).ToList();
    }

    foreach (var company in toMatch)
    {

        // CheckMatchConditions(company);

        count++;

        Console.SetCursorPosition(0, Console.CursorTop);
        Console.Write(count.ToString() + "          ");

    }
}

这会慢很多,但仍会以大致相同的循环记录速率填满内存。

当我注释掉我的实际方法时,它必须只是这些toMatch 列表在内存中挥之不去。

我在这里不知所措,有人可以说明我应该如何管理内存吗?

【问题讨论】:

  • 你能把你的匹配条件转换成 where 条件吗?类似 db.Companies.Where(CheckMatchConditions).. 你还想以某种方式处理对象吗?如果是这样,如何?

标签: c# .net memory


【解决方案1】:

添加 .AsNoTracking() 以确保 DbContext 不会跟踪实体。

using (var db = new PlaceDBContext())
{
    Messages.Output("Total: " + db.Companies.Count());
    int count = 0;
    foreach (var company in db.Companies.AsNoTracking())
    {
        count++;
        Console.SetCursorPosition(0, Console.CursorTop);
        Console.Write(count.ToString() + ". company : " + company.someProp);
    }
}

【讨论】:

  • 完美!内存现在不超过 60mb
【解决方案2】:

不要遍历对象集合,因为 EF 跟踪会在您将实体选择到对象后发生变化。 遍历一些 DTO。

db.Companies.Select(c => new CompanyDto{ Name = c.Name});

但最好不要遍历整个数据收集。只需尝试在 LINQ 中编写检查条件方法以允许 SQL 服务器进行过滤。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-09
    • 2011-12-12
    • 2012-09-25
    • 2020-10-09
    • 2019-11-19
    • 2011-01-22
    相关资源
    最近更新 更多