DataTable-Speicher nicht freigegeben werden
Ich habe einen Prozess, der das laden von Daten laden einer großen Menge von Daten in die DataTable dann einige Daten verarbeiten, aber jedes mal, wenn der job fertig ist die DataLoader.exe(32bit, 1,5 G memory limit) entbindet nicht der gesamte Speicher genutzt wird.
Versuchte ich 3 Möglichkeiten, um Speicher freizugeben:
- DataTable.Klar() dann rufen DataTable.Dispose() (Release etwa 800 MB Speicher aber noch erhöhen 200 MB Speicher jedes mal, wenn Daten laden job fertig, nach 3 oder 4 mal laden von Daten, die out-of-memory-Ausnahme ausgelöst, weil es mehr als 1,5 G Arbeitsspeicher insgesamt)
- Set DataTable zu null (Kein Speicher freigegeben, und wählen Sie laden, wenn mehr Daten, die out-of-memory-exception geworfen)
- Aufruf DataTable.Dispose() direkt (Kein Speicher freigegeben, und wählen Sie laden, wenn mehr Daten, die out-of-memory-exception geworfen)
Folgenden ist der code, ich habe versucht, für die Prüfung(In der realen Programm-es wird nicht rekursiv aufgerufen, es wird ausgelöst durch ein Verzeichnis zu beobachten Logik. Dieser code ist nur zum testen. Sorry für die Verwirrung.):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace DataTable_Memory_test
{
class Program
{
static void Main(string[] args)
{
try
{
LoadData();
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadKey();
}
}
private static void LoadData()
{
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
//Fill the data table to make it take about 1 G memory.
for (int i = 0; i < 1677700; i++)
{
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
}
Console.WriteLine("Data table load finish: please check memory.");
Console.WriteLine("Press 0 to clear and dispose datatable, press 1 to set datatable to null, press 2 to dispose datatable directly");
string key = Console.ReadLine();
if (key == "0")
{
table.Clear();
table.Dispose();
Console.WriteLine("Datatable disposed, data table row count is {0}", table.Rows.Count);
GC.Collect();
long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; //memory in megabytes
Console.WriteLine(lMemoryMB);
}
else if (key == "1")
{
table = null;
GC.Collect();
long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; //memory in megabytes
Console.WriteLine(lMemoryMB);
}
else if (key == "2")
{
table.Dispose();
GC.Collect();
long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; //memory in megabytes
Console.WriteLine(lMemoryMB);
}
Console.WriteLine("Job finish, please check memory");
Console.WriteLine("Press 0 to exit, press 1 to load more data and check if throw out of memory exception");
key = Console.ReadLine();
if (key == "0")
{
Environment.Exit(0);
}
else if (key == "1")
{
LoadData();
}
}
}
}
DataTable
selbst nicht umsetzenDispose()
es wird die Methode aus der übergeordnetenMarshalByValueComponent
- und das nur zwei DingeMarshalByValueComponent
ruftSite.Container.Remove(this)
wenn Sie die Daten der Tabelle in einemISite
(die du nicht in deinem code-Beispiel) und heben Sie denDisposed
Ereignis. Es entbindet nicht von Ressourcen.- Ich weiß nicht, aber ich Wette, Sie bekommen Ihre Objekte freigegeben, aber Sie Probleme mit der Fragmentierung des Speichers. EDIT: OH, führen Sie das Programm ohne debugger im release-Modus ist, sehen Sie sich anders Verhalten. GC verhält sich ganz anders, wenn man einen debugger attached.
- Danke. Aber in meinem Fall ist das laden von Daten innerhalb eines Verzeichnisses anschauen-exe. Um dies zu verhindern OutOfMemoery Ausnahme, was soll ich tun?
- Ok, ich werde versuchen Sie in den release-Modus.
- Läuft ohne debugger ist wichtiger, läuft im release-Modus macht kleinere änderungen, aber läuft ohne debugger macht großen Veränderungen, um das Verhalten.
- Ich habe versucht zu laufen ohne debugger (ausführen der exe direkt), noch OutOfMemory-exception geworfen.
- Lassen Sie uns weiter, diese Diskussion im chat.
- Nur nicht die Wiederverwendung der gleichen Tabelle. Erstellen Sie ein neues jedes mal. Sie gewinnen absolut nichts, durch die Wiederverwendung der gleichen DataTable jedes mal, aber Sie müssen verhindern, dass die GC von der Reinigung unerwünschte Daten, wie change-tracking-Daten.
- Mir scheint nicht, dass er erneut dieselbe DataTable
- Hoppla, es ist viel schlimmer - den rekursiven Aufruf
LoadData
bedeutet, dass ältere DataTables sind gehalten, für immer!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verschieben Sie den Teil, wenn Sie Fragen zu wiederholen, die außerhalb der Funktion, so wird der Speicher korrekt freigegeben wurden (nur getestete Methode 1(Klare und Entsorgen)):
Wohl um Objekte, die' Speicher wird freigegeben, wenn Sie außerhalb des Bereichs
table
übergeben wurde, dann das Objekt ist in der Lage zu sein, Müll gesammelt, wenn Sie einen debugger angefügt Lebensdauer aller Objekte erweitert werden, um das Ende der Methode (durch ihn mit einer rekursiven Test-Methode die Variablen werden nicht veröffentlicht, bis er beendet das Programm)GC.Collect()
. Läuft es im debugger oder läuft es im Debug-Modus aus es sprengen, genau wie die OP sieht.Ihr Hauptproblem ist das Verhalten des Garbage Collectors ist unterschiedlich, je nachdem, wenn du ein debug-oder im release-Modus ohne ein debugger vorhanden.
Wenn in einem debug-build oder release build mit einem debugger alle Objekte haben Ihre Lebensdauer verlängert, um der gesamten Lebensdauer der Methode. Was dies bedeutet ist
table
können nicht zurückgefordert werden von der GC, bis Sie abgeschlossen haben, dieLoadData
Methode. Dies ist, warum Sie keep running out of memory.Wenn Sie ändern Sie das Programm im release-Modus und führen Sie es ohne den debugger dann, sobald Sie passieren die Letzte Referenz auf das Objekt, die variable
table
Punkte auf den code-Pfad des Objekts wird für die garbage collection freigegeben und Sie erhalten die Erinnerung befreit.Der Grund, warum die GC verpasst es, das Verhalten während einer debug-Version einer" die situation nachzudenken, in der der debugger hält eine Referenz auf alle Variablen, die im Rahmen der derzeit ausgeführten code. Wenn es nicht Sie wäre nicht in der Lage sein, um den Wert einer Variablen im watch-Fenster oder der Mauszeiger über Sie. Da können Sie nicht "passieren die Letzte Referenz auf das Objekt", bis die variable geht out of scope, oder Sie überschreiben die variable.
Finden Sie in der blog-posting Auf Garbage Collection, den Umfang und die Objekt-Lebenszeiten für weitere detaillierte Informationen über den Prozess.
Es ist nicht wirklich ein Weg zu Kraft C#, um Speicher freizugeben, als würden Sie mit code, der keinen memory-management. Es hilft zu verstehen, wie die .NET garbage collector arbeitet. Im Grunde ist die Speicherauslastung .NET apps steigt eine von drei Bedingungen, die trigger eine garbage collection. Ich den Prozess beschreiben, der in der Antwort auf die folgende Frage:
Reinigung Variablen in Methoden
Einen Weg, um die
OutOfMemory
Ausnahme ist die Verwendung derMemoryFailPoint
- Klasse, die es erlaubt, scheitern Punkt, jenseits dessen eineInsufficientMemoryException
geworfen wird, geben Ihnen die Möglichkeit, zu verlangsamen den Prozess, bis ein anderer worker-thread verfügbar ist. Ich bin mir nicht sicher, ob dies ist etwas, das Sie wollen, um zu versuchen, aber es ist für Sie verfügbar:https://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396
OutOfMemory
Fehler, wenn er dies tut. Es ist eine gute Idee, verwenden Sie Objekte innerhalb eines engen Anwendungsbereichs, sondern einfach die Einstellungnull
ist nicht genug, um garbage collection auszulösen, wie ich schon oben erwähnt.Schließlich fand ich diese Tabelle mit Daten nicht Freigabe von Speicher Fehler verursacht wurde durch Oracle bulk copy. Nur für den Fall jemand hat das gleiche problem. Bitte siehe folgenden post zum Verweis
OracleBulkCopy Speicherverlust(OutOfMemory-Ausnahme)