【问题标题】:Out of Memory Exception Entity Framework When Saving保存时内存不足异常实体框架
【发布时间】:2014-11-12 18:11:27
【问题描述】:

我正在遍历实体框架中的许多不同对象,获取一些相关数据并保存这些数据。我正在为每个项目打开一个新线程,因为在方法中完成工作需要一段时间。但是,我在循环中出现了几千个项目的内存异常。我试图弄清楚这个问题发生在哪里以及如何保持多线程功能,但修复错误。任何帮助是极大的赞赏。谢谢你。

    foreach (var prod in products)
    {
        try
        {
            new Thread(() =>
            {
                ParsePage(prod);
            }).Start();


            counter++;
            Console.WriteLine(counter);
        }
        catch (Exception ex)
        {
            string message = ex.Message;
        }
    }

    public void ParsePage(Product p)
    {
        //New Repository
        IDataRepository repo = new DataRepository();

        //Grab related page report
        PageReport pr = repo.PageReports.Where(c => c.ThePageType == "Product").FirstOrDefault(c => c.ThePageTypeID == p.ProductID);

        //Do some stuff

        //Save
        repo.SavePageReport(pr);

    }

【问题讨论】:

  • 那是DataRepositoryIDisposable吗?如果是这样,请尝试将其包装在 using 语句中。
  • 它是否包含像DbContext 这样的一次性成员?如果是这样,也许它应该是一次性的。
  • 在你的抓取查询中尝试AsNoTracking()..
  • 作为旁注,您应该考虑使用任务而不是线程
  • 感谢您的建议。有什么特别的原因吗?

标签: c# .net entity-framework memory-management out-of-memory


【解决方案1】:

您可能内存不足,因为每个线程都有一个default stack size of 1 MB。 2000 个启动线程意味着 2 GB 的堆栈,可能是 max on your system

Windows* 上应用程序的内存限制

32 位

  • 静态数据 - 2GB
  • 动态数据 - 2GB
  • 堆栈数据 - 1GB(堆栈大小由链接器设置,默认为 1MB。可以使用链接器属性 System > Stack Reserve Size 增加)

请注意,在 32 位 Windows 上,所有类型数据的总和必须为 2GB 或更少。由于 Windows 本身使用的空间,实际限制约为 1.75GB

64 位

  • 静态数据 - 2GB
  • 动态数据 - 8TB
  • 堆栈数据 - 1GB(堆栈大小由链接器设置,默认为 1MB。可以使用链接器属性 System > Stack Reserve Size 增加)

另请参阅此article by Raymond Chen 和此stackoverflow question 了解更多信息。

正如 KroaX 所说,较新的 task 和较旧的 threadpool 库旨在处理此类情况。它们在线程和任务之间提供了额外的抽象级别,允许您轻松创建数千个轻量级任务,这些任务将在线程可用时分配给它们。

【讨论】:

    【解决方案2】:

    如果您对整个操作使用相同的 DbContext,则其缓存可能会导致 Out of memory 错误。在从 XML 文件中解析和存储大量数据时,我也遇到过类似的情况。

    您应该按照 dbc 的建议将存储库设为一次性,然后将其包装在 using 子句中:

    public void ParsePage(Product p)
    {
        using (var repo = new DataRepository())
        {
            //Grab related page report
            PageReport pr = repo.PageReports.Where(c => c.ThePageType == "Product").FirstOrDefault(c => c.ThePageTypeID == p.ProductID);
    
            //Do some stuff
    
            //Save
            repo.SavePageReport(pr);
        }
    }
    

    关于如何实现 Disposable 模式的信息可以找到here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-03
      • 2010-10-05
      相关资源
      最近更新 更多