wake-up-neo.net

Eine Fehlermeldung des Typs 'SystemOutOfMemoryException' wurde angezeigt

Grundsätzlich verwende ich Entity Framework, um eine riesige Datenbank abzufragen. Ich möchte eine Stringliste zurückgeben und dann in einer Textdatei protokollieren.

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);
}

Ich erhielt jedoch eine Ausnahme, wenn logFilePathFileName.Count=397000. Die Ausnahme ist:

Eine Fehlermeldung des Typs 'SystemOutOfMemoryException' wurde angezeigt.

Eine erste Gelegenheitsausnahme des Typs 'System.OutOfMemoryException' Trat in System.Data.Entity.dll auf

UPDATE:

Was ich mit einer anderen Abfrage sagen möchte: Wählen Sie Top 1000 aus und fügen Sie sie zur Liste hinzu, aber ich weiß nach 1000 nicht, was dann?

7
user1108948

Am wahrscheinlichsten handelt es sich nicht um eine RAM, wie es ist, also hat das Erhöhen der RAM oder das Kompilieren und Ausführen Ihres Codes in der 64-Bit-Maschine in diesem Fall keine positive Wirkung. 

Ich denke, es hängt mit einer Tatsache zusammen, dass .NET Sammlungen auf den maximalen 2GB RAM Speicherplatz beschränkt sind (kein Unterschied entweder 32 oder 64 Bit).

Um dies zu beheben, teilen Sie Ihre Liste in viel kleinere Brocken auf und am wahrscheinlichsten Ihr Problem wird verschwinden.

Nur eine mögliche Lösung:

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 !|
    }
}

EDIT 

Wenn Sie ein query fragmentieren möchten, können Sie Skip(...) und Take(...) verwenden.

Nur ein erklärendes Beispiel: 

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

...und so weiter.. 

Setzen Sie es natürlich in Ihre Iteration ein und parametrieren Sie es basierend auf den Grenzen der Daten, die Sie kennen oder benötigen.

13
Tigran

Warum sammeln Sie die Daten in einem List<string>, wenn Sie sie nur in eine Textdatei schreiben müssen?

Sie könnten genauso gut:

  • Öffnen Sie die Textdatei.
  • Durchlaufen Sie die Datensätze und hängen Sie jede Zeichenfolge an die Textdatei an (ohne die Zeichenfolgen im Speicher zu speichern).
  • Spülen und schließen Sie die Textdatei.

Sie benötigen viel weniger Speicher als jetzt, da Sie all diese Zeichenfolgen nicht unnötig im Speicher behalten.

3
Roy Dictus

Möglicherweise müssen Sie einige Vmargs für den Speicher festlegen! Außerdem ... sollten Sie direkt in Ihre Datei schreiben und nicht in einer Liste speichern

1
Bob Flannigon

Was Roy Dictus sagt, klingt am besten. Sie können auch versuchen, Ihrer Abfrage ein Limit hinzuzufügen. Ihr Datenbankergebnis wird also nicht so groß sein.

Für Informationen zu: Begrenzung der Abfragegröße mit Entitätsframework

1

Sie sollten nicht alle Datensätze aus der Datenbank in die Liste einlesen. Es erforderte viel Speicher. Sie können Lesendatensätze kombinieren und in eine Datei schreiben. Lesen Sie zum Beispiel 1000 Datensätze von db in die Liste und speichern Sie sie (fügen Sie sie in eine Textdatei ein), löschen Sie den verwendeten Speicher (list.Clear ()) und fahren Sie mit den neuen Datensätzen fort.

0
Warr

Ich habe die gc arraylist in VS c ++ verwendet, ähnlich der gc-Liste, die Sie verwendet haben, um mit kleinen und mittleren Datensätzen zu arbeiten. Bei der Verwendung von Big Dat wurde jedoch dasselbe Problem 'System.OutOfMemoryException' ausgelöst. Da die Größe dieser gcs nicht größer als 2 GB sein kann und daher mit Big Data ineffizient wird, habe ich eine eigene verknüpfte Liste erstellt, die dieselbe Funktionalität, dynamische Erhöhung und get by index bietet. Im Grunde handelt es sich dabei um eine normale verknüpfte Listenklasse mit einer Ein dynamisches Array, um Daten per Index abzurufen, dupliziert den Speicherplatz, aber Sie können die verknüpfte Liste nach dem Aktualisieren des Arrays löschen, wenn Sie nicht das dynamische Array benötigen. Dies würde das Problem lösen. siehe den code:

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++;
    }
}

Wenn Sie dies verwenden, beziehen Sie sich bitte auf meine Arbeit https://www.liebertpub.com/doi/10.1089/big.2018.0064

0
Ahmad Hassanat

Aus verschiedenen anderen Themen zu StackOverflow habe ich gelesen, dass das Entity Framework nicht für die Verarbeitung solcher Massendaten ausgelegt ist. Die EF speichert/verfolgt alle Daten im Kontext und führt bei sehr großen Datenmengen zu einer Ausnahme. Sie können SQL direkt verwenden oder Ihre Datensätze in kleinere Sätze aufteilen.

0
Abbas