warum bekomme ich System.OutOfMemoryException, selbst wenn es über 700Mb freien RAM?
Ich lief einige Tests, um zu sehen, wie meine Protokollierung führen würde, ist statt File.AppendAllText
ich würde zuerst schreiben, um einen memory-stream und klicken Sie auf in Datei kopieren. So, nur um zu sehen, wie schnell der Speicher-Betrieb ist, ich habe diese..
private void button1_Click(object sender, EventArgs e)
{
using (var memFile = new System.IO.MemoryStream())
{
using (var bw = new System.IO.BinaryWriter(memFile))
{
for (int i = 0; i < Int32.MaxValue; i++)
{
bw.Write(i.ToString() + Environment.NewLine);
}
bw.Flush();
}
memFile.CopyTo(new System.IO.FileStream(System.IO.Path.Combine("C", "memWriteWithBinaryTest.log"), System.IO.FileMode.OpenOrCreate));
}
}
Wenn i
erreicht 25413324
bekam ich einen Exception of type 'System.OutOfMemoryException' was thrown.
obwohl mein Process Explorer sagt, ich habe über 700 MB freien ram???
Hier sind die screenshots (nur für den Fall)
Process Explorer
Hier ist der winform -
EDIT : zuliebe mehr Objekte erstellt werden, der auf Haufen, und ich schrieb die bw.write
dieser
bw.Write(i);
- Als pro Antwort, die
BinaryWriter
schreibt nicht aus der string-Repräsentation der Zahl. Es schreibt die byte-Darstellung. Vielleicht will man das letztere, aber aus dem ursprünglichen code ist, erscheint es nicht so.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Zunächst, Sie aus dem Gedächtnis, weil das sammeln der Daten in der
MemoryStream
, statt zu schreiben direkt auf derFileStream
. Verwenden Sie dieFileStream
direkt und Sie brauchen nicht viel RAM haben (aber Sie haben zu halten die Datei öffnen).Die Menge des physischen Speichers ungenutzt ist nicht direkt relevant für diese Ausnahme, so seltsam das auch klingen mag.
Was zählt, ist:
Wenn Sie Fragen, wird der Windows-Speicher-manager zuweisen Sie einige RAM, die es braucht, um zu überprüfen, nicht, wie viel ist verfügbar, aber wie viel hat es versprochen zur Verfügung zu stellen und jeder andere Prozess. Wie vielversprechend ist durch verpflichtet. Zu Begehen einige Speicher bedeutet, dass der Speicher-manager bietet Ihnen eine Garantie, dass es wird verfügbar sein, wenn Sie schließlich machen, Sie zu nutzen.
So, kann es sein, dass der physikalische RAM ist komplett verbraucht, aber Ihre Reservierungsanforderung noch gelingt. Warum? Da es viel Speicherplatz in der Auslagerungsdatei. Wenn Sie tatsächlich beginnen mit dem RAM Sie haben durch eine solche Verteilung der Speicher-manager wird einfach nur die Seite aus etwas anderes. Also 0 physikalische RAM != Zuweisungen fehlschlagen.
Das Gegenteil kann passieren, zu; eine Zuordnung fehlschlagen kann, trotz einiger ungenutzter Physischer RAM. Ihr Prozess sieht-Speicher durch die so genannte virtuellen Adressraum. Wenn ein Prozess liest den Speicher an der Adresse
0x12340000
, das ist eine virtuelle Adresse. Es könnte die Karte um den RAM auf0x78650000
oder bei0x000000AB12340000
(mit einer 32-bit-Prozess auf einem 64-bit-OS), es verweist auf etwas, das existiert nur in der page-Datei, oder könnte es nicht sogar Punkt, an überhaupt nichts.Wenn Sie möchten, reserviert einen Speicherblock, der mit aufeinanderfolgenden Adressen, die es in dieser virtuellen Adressraum, der RAM muss zusammenhängend sein. Für eine 32-bit-Prozess, erhalten Sie nur 2GB oder 3GB nutzbaren Adressraum, so dass es nicht zu schwer zu verwenden Sie es in einer Weise, die keinen zusammenhängenden Stück von ausreichender Größe vorhanden ist, obwohl es sowohl freien physikalischen RAM und genug insgesamt nicht verwendete virtuelle Adressraum.
Dies kann verursacht werden durch eine Fragmentierung des Speichers.
Große Objekte gehen auf den large object heap und Sie nicht verschoben werden, um Platz zu schaffen für die Dinge. Dies kann zur Fragmentierung führen, wo haben Sie Lücken in den verfügbaren Speicher, die kann dazu führen, out-of-memory, wenn Sie versuchen, reservieren Sie ein Objekt größer als bei jedem der Blöcke des verfügbaren Speichers.
Siehe hier für mehr details.
Jedes Objekt größer als 85.000 Byte beträgt, wird auf dem large object heap, außer für die arrays von doubles für die der Schwellenwert nur 1000 verdoppelt (oder 8000 bytes).
Beachten Sie auch, dass 32-bit .Net-Programme sind beschränkt auf maximal 2GB pro Objekt und etwas weniger als 4 GB insgesamt (vielleicht so niedrig wie 3 GB, je nach OS).
Sollten Sie nicht verwenden eine
BinaryWriter
um text in eine Datei schreiben. Verwenden Sie eineTextWriter
statt.Nun sind Sie mit:
for (int i = 0; i < Int32.MaxValue; i++)
Diesem schreiben mindestens 3 Byte pro schreiben (Zahlendarstellung und newline). Mal, dass durch
Int32.MaxValue
und man braucht mindestens 6 GB Arbeitsspeicher schon zu sehen, Sie schreiben es zu einemMemoryStream
.Suche weiter auf Ihren code, den Sie schreiben werden, die
MemoryStream
zu einer Datei in keiner Weise. So können Sie einfach Folgendes tun:oder schreiben Sie eine offene
TextWriter
:Wenn Sie möchten, dass einige Speicher-Puffer, die IMO ist eine schlechte Idee für die Protokollierung, da verlieren Sie das Letzte bisschen der schreibt bei einem crash, können Sie mithilfe der folgenden erstellen Sie die
TextWriter
:bestehen und ein 'biggish' Zahl für
bufferSize
. Der Standardwert ist1024
.Um die Frage zu beantworten, erhalten Sie eine out-of-memory-Ausnahme aufgrund der
MemoryStream
ändern und irgendwann wird es zu groß, um zu passen in den Speicher (das wurde diskutiert, in einer anderen Antwort).