抛出了类型'System.OutOfMemoryException'的异常

时间:2013-01-30 14:10:55

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

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

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后呢?

7 个答案:

答案 0 :(得分:13)

最可能的是它不是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);

... 等等..

自然地将它放在你的迭代中,并根据你知道或需要的数据边界对其进行参数化。

答案 1 :(得分:3)

如果您需要做的只是将其写入文本文件,为什么要在List<string>中收集数据?

您可能只是:

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

从StackOverflow上的其他几个主题我读到实体框架不是为处理那样的批量数据而设计的。 EF将缓存/跟踪上下文中的所有数据,并在出现大量数据时导致异常。选项是直接使用SQL或将记录拆分为较小的集合。

答案 6 :(得分:0)

我曾经在VS c ++中使用类似于您所使用的gc列表的gc arraylist来处理小型和中间数据集,但是当使用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