簡體   English   中英

拋出了類型'System.OutOfMemoryException'的異常

[英]Exception of type 'System.OutOfMemoryException' was thrown

基本上我使用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.Data.Entity.dll中發生了'System.OutOfMemoryException'類型的第一次機會異常

更新:

我想用一個不同的查詢說:選擇前1000然后添加到列表中,但我不知道1000之后又是什么?

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

... 等等..

自然地將它放在迭代中並根據您知道或需要的數據邊界對其進行參數化。

如果您只需要將其寫入文本文件,為什么要在List<string>收集數據?

你可能只是:

  • 打開文本文件;
  • 迭代記錄,將每個字符串附加到文本文件中(不將字符串存儲在內存中);
  • 刷新並關閉文本文件。

您將需要比現在少得多的內存,因為您不會在內存中不必要地保留所有這些字符串。

您可能需要為內存設置一些vmargs! 另外......請直接將其寫入您的文件,而不是將其保存在列表中

Roy Dictus說的聽起來是最好的方式。 您也可以嘗試為查詢添加限制。 所以你的數據庫結果不會那么大。

有關以下內容的信息: 使用實體框架限制查詢大小

您不應該從數據庫到列表中讀取所有記錄。 它需要大量的內存。 你聯合閱讀記錄並將它們寫入文件。 例如,從db到list中讀取1000條記錄,並將它們保存(追加)到文本文件,清除已用內存(list.Clear())並繼續新記錄。

從StackOverflow上的其他幾個主題我讀到實體框架不是為處理那樣的批量數據而設計的。 EF將緩存/跟蹤上下文中的所有數據,並在出現大量數據時導致異常。 選項是直接使用SQL或將記錄拆分為較小的集合。

我曾經在VS c ++中使用gc arraylist,類似於你使用的gc List,用於處理小型和中型數據集,但是當使用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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM