Mögliche Gründe für FileStream.Write () eine OutOfMemoryException zu werfen?
-
23-08-2019 - |
Frage
Ich habe 10 Fäden Tausende von kleinen Puffern (16-30 Bytes jeweils) zu einer großen Datei in zufälligen Positionen zu schreiben. Einige der Themen werfen OutOfMemoryException auf FileStream.Write () opreation.
Was ist die Ursache der OutOfMemoryException? Was es zu sehen?
Ich bin das Filestream wie folgt aus (für jeden geschriebenen Artikel - dieser Code ausgeführt wird aus 10 verschiedenen Themen):
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, BigBufferSizeInBytes, FileOptions.SequentialScan))
{
...
fs.Write();
}
Ich vermute, dass alle Puffer innerhalb des Filestream zugeordnet nicht durch die GC in der Zeit frei bekommen. Was ich nicht verstehe ist, warum die CLR, anstelle des Werfens, läuft nicht nur einen GC-Zyklus und frei bis alle nicht verwendeten Puffer?
Keine korrekte Lösung
Andere Tipps
Wenn zehn Threads Öffnen von Dateien als Code zeigt, dann haben Sie maximal zehn undisposed Filestream-Objekte zu einem beliebigen Zeitpunkt. Ja, Filestream hat hat einen internen Puffer, die Größe, die Sie mit „BigBufferSizeInBytes“ im Code angeben. Könnten Sie bitte den genauen Wert offen legen? Wenn diese groß genug ist (z ~ 100 MB), dann könnte es auch die Ursache des Problems sein.
In der Standardeinstellung (das heißt, wenn Sie keine Nummer auf Konstruktion angeben), ist dieser Puffer 4 KB und das ist in der Regel gut für die meisten Anwendungen. Im Allgemeinen, wenn Sie wirklich über Plattenschreibleistung kümmern, dann könnten Sie diese ein, um ein paar 100kB erhöhen, aber nicht mehr.
Doch für Ihre spezifische Anwendung tun würde so nicht viel Sinn machen, da der Puffer wird nie mehr enthalten als die 16-30 Bytes, die Sie in sie schreiben, bevor Sie das Objekt Filestream Entsorgen ().
Um Ihre Frage zu beantworten, wird ein OutOfMemoryException nur ausgelöst, wenn der angeforderte Speicher nicht zugeordnet werden kann, nach ein GC ausgeführt wird. Noch einmal, wenn der Puffer wirklich groß ist, dann könnte das System viele Speicher halten kann, nur nicht ein zusammenhängende Brocken. Dies liegt daran, das große Objektheap nie verdichtet wird.
Ich habe über diesen erinnere die Menschen ein paar Mal, aber die
Die Puffer sind im Allgemeinen nicht innerhalb des Filestream zugeordnet. Vielleicht ist das Problem ist die Linie „Tausende von kleinen Puffer zu schreiben“ - meinst du das wirklich? Normalerweise Sie einen Puffer viele wiederverwenden, viele, viele Male (das heißt auf verschiedenen Anrufe Lesen / Schreiben). Auch - das ist eine einzelne Datei? Eine einzelne Filestream ist nicht auf die Threadsicherheit garantiert ... also, wenn Sie nicht Synchronisierung tun, erwarten Chaos.
Es ist möglich, dass diese Einschränkungen aus dem zugrunde liegenden Betriebssystem auftreten, und dass das .NET Framework ist machtlos, diese Art von Einschränkungen zu überwinden.
Was kann ich nicht aus dem Code Probe ableiten, ob Sie eine Menge dieser Objekte Filestream zur gleichen Zeit öffnen, oder öffnen Sie sie wirklich schnell nacheinander. Ihre Nutzung des ‚mit‘ Schlüsselwort wird sicherstellen, dass die Dateien nach dem fs.Write () -Aufruf geschlossen sind. Es gibt keinen GC-Zyklus benötigt, um die Datei zu schließen.
Die Filestream-Klasse ist wirklich auf sequentiellen Lese- / Schreibzugriff auf Dateien ausgerichtet. Wenn Sie schnell an zufälligen Orten in einer großen Datei schreiben müssen, könnten Sie einen Blick auf mit virtueller Dateizuordnung nehmen.
Update: Es scheint, dass virtuelle Dateizuordnung nicht offiziell bis 4.0 in .NET unterstützt werden. Sie können einen Blick auf Dritte-Implementierungen für diese Funktionalität nehmen.
Dave
Ich erlebe etwas ähnliches und fragte sich, ob Sie überhaupt die Wurzel des Problems festgenagelt?
Mein Code funktioniert ziemlich viel Kopieren zwischen Dateien, ganz wenige megs zwischen verschiedenen Byte-Dateien übergeben. Ich habe bemerkt, dass, während die Prozess Speichernutzung in einem vernünftigen Rahmen bleibt, schießt die System Speicherzuweisung auf viel zu hoch während des Kopier - viel mehr als durch meinen Prozess verwendet wird.
ich das Problem verfolgt habe bis auf die FileStream.Write () -Aufruf - wenn diese Linie herausgenommen wird, scheint die Speichernutzung als erwartet zu gehen. Mein BigBufferSizeInBytes ist die Standardeinstellung (4k), und ich kann nicht überall sehen, wo diese zu sammeln könnten ...
Alles, was Sie während der Suche auf Ihrem Problem entdeckt dankbar empfangen würde!