【问题标题】:Exception of type 'System.OutOfMemoryException' was thrown引发了“System.OutOfMemoryException”类型的异常
【发布时间】:2013-01-14 09:17:18
【问题描述】:

基本上我使用实体框架来查询一个巨大的数据库。我想返回一个字符串列表,然后将其记录到一个文本文件中。

List<string> logFilePathFileName = new List<string>();
var query = from c in DBContext.MyTable where condition = something select c;
foreach (var result in query)
{
    filePath = result.FilePath;
    fileName = result.FileName;
    string temp = filePath + "." + fileName;
    logFilePathFileName.Add(temp);
    if(logFilePathFileName.Count %1000 ==0)
        Console.WriteLine(temp+"."+logFilePathFileName.Count);
}

但是当logFilePathFileName.Count=397000 时出现异常。 例外是:

引发了“System.OutOfMemoryException”类型的异常。

“System.OutOfMemoryException”类型的第一次机会异常 发生在 System.Data.Entity.dll 中

更新:

我想用一个不同的查询说:选择前 1000 个然后添加到列表中,但我不知道 1000 之后是什么?

【问题讨论】:

  • 提示:升级你的内存 :-)
  • 您能否提供有关异常的完整信息以及内部异常(如果有)以及堆栈跟踪。
  • temp 的一般长度是多少?
  • 内存4GB,够用了……

标签: c# sql-server entity-framework c#-4.0 ef-code-first


【解决方案1】:

很可能这与RAM 无关,因此在这种情况下,增加RAM 甚至在64 位机中编译和运行代码都不会产生积极影响。

我认为这与 .NET 集合被限制在最大 2GB RAM 空间(3264 位没有区别)这一事实有关。

要解决此问题,请将您的列表拆分为更小的块,很可能您的问题就会消失。

只有一种可能的解决方案:

foreach (var result in query)
{
    ....
    if(logFilePathFileName.Count %1000 ==0) {
        Console.WriteLine(temp+"."+logFilePathFileName.Count);
        //WRITE SOMEWHERE YOU NEED 
        logFilePathFileName = new List<string>(); //RESET LIST !|
    }
}

编辑

如果你想分段一个查询,你可以使用Skip(...)Take(...)

只是一个解释性的例子:

var fisrt1000 = query.Skip(0).Take(1000);
var second1000 = query.Skip(1000).Take(1000);

... 等等……

自然地将其放入您的迭代中,并根据您知道或需要的数据范围对其进行参数化。

【讨论】:

  • 问题是数据库似乎也因为繁重的查询而死了。
  • 那么您在 server 上遇到异常?
  • 还没有,可能是别的。请看我的更新,我想选择前 1000 个批量然后迭代其余的,如何?
  • 您可以使用 Skip(..)Take(..) 对查询进行分段或查询,或者在一个查询中获取所有查询但分段列表.
  • 我是说1000之后,怎么查询选择1001-2000?您仍然不能使用 select top 1000...
【解决方案2】:

如果您只需将数据写入文本文件,为什么还要在 List&lt;string&gt; 中收集数据?

你也可以:

  • 打开文本文件;
  • 遍历记录,将每个字符串附加到文本文件(不将字符串存储在内存中);
  • 刷新并关闭文本文件。

您将需要比现在少得多的内存,因为您不会在内存中不必要地保留所有这些字符串。

【讨论】:

    【解决方案3】:

    您可能需要为内存设置一些 vmargs! 另外...考虑将其直接写入您的文件而不是将其保存在列表中

    【讨论】:

      【解决方案4】:

      Roy Dictus 所说的听起来是最好的方式。 您也可以尝试为您的查询添加限制。所以你的数据库结果不会那么大。

      有关以下信息: Limiting query size with entity framework

      【讨论】:

        【解决方案5】:

        您不应该将数据库中的所有记录都读取到列表中。它需要大量的内存。你结合阅读记录并将它们写入文件。例如从 db 读取 1000 条记录到列表并将它们保存(附加)到文本文件,清除使用的内存(list.Clear())并继续新记录。

        【讨论】:

          【解决方案6】:

          从 StackOverflow 上的其他几个主题中,我了解到实体框架并非旨在处理这样的批量数据。 EF 将缓存/跟踪上下文中的所有数据,并在大量数据的情况下导致异常。选项是直接使用 SQL 或将记录拆分为较小的集合。

          【讨论】:

            【解决方案7】:

            我曾经在 VS c++ 中使用 gc 数组列表,类似于您使用的 gc 列表,用于处理小型和中间数据集,但是在使用 Big Dat 时,抛出了同样的问题“System.OutOfMemoryException”。 由于这些 gcs 的大小不能超过 2 GB,因此对大数据效率低下,我构建了自己的链表,它提供了相同的功能,动态增加和按索引获取,基本上,它是一个普通的链表类,具有内部的动态数组提供通过索引获取数据,它复制了空间,但是您可以在更新数组后删除链表,您不需要它只保留动态数组,这将解决问题。看代码:

            struct LinkedNode
            {
                long data;
                LinkedNode* next;
            };
            
            
            class LinkedList
            {
            public:
                LinkedList();
                ~LinkedList();
                LinkedNode* head;
                long Count;
                long * Data;
                void add(long data);
                void update();
                //long get(long index);
            };
            
            LinkedList::LinkedList(){
                this->Count = 0;
                this->head = NULL;
            }
            
            LinkedList::~LinkedList(){
                LinkedNode * temp; 
                while(head){
                    temp= this->head ;
                    head = head->next;
                    delete temp;
                }
                if (Data)
                    delete [] Data; Data=NULL;
            }
            
            void LinkedList::add  (long data){
                LinkedNode * node = new LinkedNode();
                node->data = data;
                node->next = this->head;
                this->head = node;
                this->Count++;}
            
            void LinkedList::update(){
                this->Data= new long[this->Count];
                long i = 0;
                LinkedNode * node =this->head;
                while(node){
                    this->Data[i]=node->data;
                    node = node->next;
                    i++;
                }
            }
            

            如果你用这个,请参考我的作品https://www.liebertpub.com/doi/10.1089/big.2018.0064

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-08-28
              • 2015-07-18
              • 2011-02-14
              • 2015-07-12
              相关资源
              最近更新 更多