wake-up-neo.com

Speicherplatz in c # explizit freigeben

Ich habe eine C # -Anwendung erstellt, die 150 MB Speicher (private Bytes) benötigt, hauptsächlich aufgrund eines großen Wörterbuchs:

Dictionary<string, int> Txns = new Dictionary<string, int>();

Ich habe mich gefragt, wie ich diesen Speicher freigeben kann. Ich habe das probiert:

Txns = null;
GC.Collect();

Aber in meinen privaten Bytes scheint es keine großen Beulen zu geben - sie fallen von etwa 155 MB auf 145 MB ... _. Irgendwelche Hinweise?

Vielen Dank

-bearbeiten-

Okay, ich habe mehr Glück mit diesem Code (die privaten Bytes werden auf 50 MB reduziert), aber warum?

Txns.Clear(); // <- makes all the difference
Txns = null;
GC.Collect();

-bearbeiten-

Okay für alle, die sagen: "GC.collect nicht verwenden", fair genug (ich werde darüber nicht debattieren, abgesehen davon, dass Sie meinen C-Hintergrund durchschauen sehen), aber es beantwortet meine Frage nicht wirklich: Warum gibt der Garbage Collector den Speicher nur frei, wenn ich die Transaktionsliste zuerst lösche? Sollte der Speicher nicht trotzdem freigegeben werden, da das Wörterbuch dereferenziert wurde?

36
Chris

Private Bytes spiegeln die Speicherbelegung des Prozesses wider. Wenn Objekte gesammelt werden, kann das zugehörige Speichersegment für das Betriebssystem freigegeben werden oder nicht. Die CLR verwaltet Speicher auf Betriebssystemebene. Da das Zuordnen und Freigeben von Speicher nicht frei ist, gibt es keinen Grund, jeden Speicherplatz sofort freizugeben, da die Anwendung wahrscheinlich später mehr Speicherplatz anfordert. 

17
Brian Rasmussen

wenn Sie GC.Collect () aufrufen, wird der Job sofort ausgeführt, es wird jedoch sofort zurückgegeben. Es wird jedoch nicht blockiert. Wenn Sie also nur GC.WaitForPendingFinalizers () aufrufen, wird Ihre Anwendung erst nach GC blockiert. Collect () beendet seine Arbeit

11
Sadegh

Wahrscheinlich haben Sie einen versteckten Verweis auf das Wörterbuch an anderer Stelle. So wird das Wörterbuch nicht gesammelt, aber wenn Sie es Clear(), werden die Inhalte gesammelt.

Wie bereits erwähnt, wird das Erzwingen der GC nicht empfohlen. Dies könnte dazu führen, dass der Speicher in höhere "Generationen" verschoben wird, die nicht oft gesammelt werden, wodurch mehr Speicherplatz verschwendet wird, als auf lange Sicht gewonnen wird.

5
David Schmitt

Nicht sicher aus dem Speicher, wenn Dictionary eine Dispose() hat oder nicht, aber es hat zwingend eine Clear(). Rufen Sie eine dieser Optionen auf, bevor Sie Verweise auf null setzen.

Dann lassen Sie den Müllsammler einfach seine Arbeit erledigen. Es ist fast never eine gute Idee, GC.Collect() explizit selbst zu nennen, und es kann nicht einmal das tun, was Sie wollen/wollen/erwarten/erwarten und die Leistung kostet. Statische Codeanalyse (= FxCop) warnt Sie nicht mit Zuverlässigkeitsregel CA2001 über nichts, wissen Sie? Tun Sie dies einfach nicht, es sei denn, Sie wissen wirklich, was Sie tun. Und mach es auch nicht. ;-)

Sind Sie sicher, dass das Wörterbuch so groß ist? Sind es nicht nur 10 MB Speicher und der Rest wird sonst von Ihrer Anwendung übernommen? Frage, die Ihnen vielleicht helfen könnte: Haben Sie bereits einen Profiler verwendet, um zu sehen, wo tatsächlich Speicher verbraucht wird ...?

4
peSHIr

Benötigen Sie den Speicher zurück? Der Speicher ist verfügbar, er wird einfach nicht zurückgefordert. Sie sollten das Wörterbuch nicht löschen, eine schwache Referenz dazu haben und die Runtime ihre Arbeit erledigen lassen.

Wenn Sie wirklich genau wissen wollen, was vor sich geht, sehen Sie sich den .NET Memory Profiler an. Auf diese Weise können Sie genau sehen, was genau mit Ihrem Objekt passiert, welche Generation es ist, welcher Speicher von was und immer verwendet wird. :)

1
JP Alioto

Ok, ich habe hier eine Theorie ... Das Dictionary ist eine Sammlung von KeyValuePair, die wiederum ein Referenztyp ist.

Ihr Wörterbuch enthält diese keyValuePairs. Wenn du sagst:

Txns = null

Dadurch wird der Verweis 'Txns' aus der KeyValuePair-Auflistung freigegeben. Dennoch wird der tatsächliche Speicher von 150 MB von diesen KeyValuePair-Servern referenziert, und sie sind in ihrem Umfang und somit nicht für die Speicherbereinigung bereit.

Wenn Sie jedoch Folgendes verwenden:

Txns.Clear();
Txns = null;
GC.Collect();

Hier löscht die clear-Methode auch die 150 MB Daten aus den entsprechenden KeyValuePair-Objektreferenzen. Somit waren diese Objekte zur Müllsammlung bereit.

Es ist nur eine wilde Vermutung, die ich hier mache. Kommentare sind willkommen :)

1
Savaratkar

Bearbeiten:

Wenn Sie den Verweis auf null setzen, wird der Speicher nicht freigegeben, sondern der Container wird einer anderen Adresse zugewiesen, in diesem Fall null. Gemäß MSDN führt Clear() Folgendes aus: "Die Count-Eigenschaft ist auf 0 gesetzt, und Verweise auf andere Objekte aus Elementen der Auflistung werden ebenfalls freigegeben. Die Kapazität bleibt unverändert."

...

Sie sollten niemals den Garbage Collector anrufen. Sie verwenden verwaltete Objekte ohne native Ressourcen. Sie können sich darauf verlassen, dass der Garbage Collector nach Ihnen bereinigt wird.

Abgesehen von der Größe Ihres Wörterbuchs müssen Sie sich nicht um den Speicher kümmern, Speicher ist nicht Ihr Problem, sondern das Problem der Speicherbereinigung.

Beim Aufruf von Clear() werden die Verweise auf alle enthaltenen Objekte entfernt, die Kapazität bleibt jedoch unverändert.

Technisch gesehen ist das Sammeln von Speicher teuer und ein beträchtlicher zeitaufwändiger Betrieb. Der Grund dafür ist, dass der GC nicht nur Heapspeicher verwaltet und Ihren Heap aufräumt, sondern auch den Heap irgendwie defragmentiert. Es versucht, den Speicher in zusammenhängende Blöcke zu verschieben, um die Zuweisung für einen großen Code zu beschleunigen, der eine große Anforderung stellt.

p.s. Wie groß ist Ihr Wörterbuch, das Sie mit 155 MB Arbeitsspeicher verwenden?

1
Chris

Es ist normalerweise keine gute Idee, den GC zu erzwingen. Müssen Sie wirklich das gesamte Wörterbuch im Speicher haben?

0
ivmos

Windows verfügt über zwei Ereignisse für die Verfügbarkeit des Speichers. Ich würde erwarten, dass die CLR darauf reagiert. Wenn genügend Speicher verfügbar ist, sollten Sie den Garbage Collector NICHT ausführen. Um sicher zu gehen, dass Sie tatsächlich ein schlechtes CLR-Verhalten beobachten, wiederholen Sie diesen Test mit einer anderen Dummy-Anwendung, die einen großen Haufen Speicher verwendet.

0
MSalters