Best Practices zur Erleichterung der Speicherbereinigung in .Net

In Microsoft.Net ist die Speicherbereinigung ein Mechanismus, der von der Common Language Runtime (CLR) übernommen wird, um die von Ihrer Anwendung verbrauchten Ressourcen zu bereinigen. Wenn Sie Objekte in .Net erstellen, werden diese im verwalteten Heap gespeichert. Während Sie Objekte erstellen müssen, müssen Sie sich in den meisten Fällen keine Sorgen um die Bereinigung der Objekte machen - die Laufzeit würde dies für Sie tun.

Sie sollten jedoch Best Practices in Ihre Anwendung übernehmen, um die Speicherbereinigung zu vereinfachen und die Ressourcen schneller zu bereinigen. Obwohl .Net in der Lage ist, verwaltete Objekte zurückzugewinnen, sollten Sie bestimmte Richtlinien befolgen, um eine schnellere Speicherbereinigung zu ermöglichen und die Leistung Ihrer Anwendung zu verbessern. In diesem Artikel möchte ich eine Diskussion über die Funktionsweise der Speicherbereinigung und die Best Practices zur Erleichterung der Speicherbereinigung in .Net vorstellen.

Wann findet die Müllabfuhr statt?

Die Speicherbereinigung findet statt, wenn das System über wenig verfügbaren physischen Speicher verfügt oder die GC.Collect()Methode im Code Ihrer Anwendung explizit aufgerufen wird. Objekte, die nicht mehr verwendet werden oder vom Stamm aus nicht mehr erreichbar sind, sind Kandidaten für die Speicherbereinigung. Im Wesentlichen bereinigt der Garbage Collector den Speicher, der von Objekten belegt wird, die keine Referenzen haben.

Generationen

Die Laufzeit organisiert den verwalteten Heap in Generationen. Diese Generationen werden verwendet, um kurz- und langlebige Objekte zu organisieren. Es ist zu beachten, dass der Garbage Collector in den unteren Generationen viel häufiger arbeitet als in den höheren. Generation 0 enthält die kurzlebigen Objekte wie temporäre Objekte. Wenn ein Objekt erstellt wird, wird es in Generation 0 gespeichert, es sei denn, es ist ein großes Objekt. Wenn es sich bei dem Objekt um ein großes Objekt handelt, wird es in Generation 2 im Large Object Heap (LOH) gespeichert. In den meisten Fällen werden die Objekte der Generation 0 vom Garbage Collector zurückgefordert, wenn sie im Hintergrund ausgeführt werden.

Wenn Sie Code schreiben, sollten Sie bestimmte Best Practices einhalten. Beispielsweise sollten Sie Objekte im lokalen Bereich so weit wie möglich erstellen, um die Speicherbereinigung zu vereinfachen. Objekte, die im höheren Bereich erstellt wurden, befinden sich im Allgemeinen für einen längeren Zeitraum im Speicher. Sie können den CLR-Profiler verwenden, um die Zuordnungsmuster Ihrer Anwendung zu verstehen.

Sie sollten es vermeiden, die GC.Collect()Methode aufzurufen , da sie eine vollständige Sammlung aller Generationen (Generation 0, 1 und 2) verursacht. Wenn Sie die GC.Collect()Methode aufrufen, besucht die Laufzeit alle Live-Objekte in Ihrer Anwendung. Dies nimmt viel Zeit in Anspruch und ist daher eine sehr teure Operation. Daher ist es keine gute Praxis, die GC.Collect()Methode aufzurufen .

Wenn Sie die GC.Collect()Methode aufrufen müssen , sollten Sie GC.WaitForPendingFinalizers()nach dem Aufruf aufrufen, GC.Collect()um sicherzustellen, dass der aktuell ausgeführte Thread wartet, bis die Finalizer für alle Objekte ausgeführt wurden.

Als Nächstes sollten Sie die GC.Collect()Methode erneut aufrufen, um sicherzustellen, dass Sie die verbleibenden toten Objekte sammeln. Diese toten Objekte, die möglicherweise aufgrund des Aufrufs der Finalizer-Methode für die Objekte erstellt wurden. Das folgende Codefragment zeigt, wie diese Methoden verwendet werden.

System.GC.Collect();

System.GC.WaitForPendingFinalizers();

System.GC.Collect();

Sie sollten sicherstellen, dass Sie versteckte Zuordnungen minimieren und Ihren Code so schreiben, dass die Wahrscheinlichkeit einer Beförderung kurzlebiger Objekte zu höheren Generationen ausgeschlossen ist. Sie sollten nicht auf kurzlebige Objekte von langlebigen Objekten verweisen, um eine Förderung der kurzlebigen Objekte für höhere Generationen zu vermeiden.

Sie sollten auch vermeiden, Finalizer für Ihre Klassen zu schreiben. Wenn Sie einen Finalizer in Ihrer Klasse implementiert haben, werden Objekte solcher Klassen zu langlebigen Objekten, da die Laufzeit die finalisierbaren Objekte für ältere Generationen heraufstufen muss. Sie sollten Objekte auf null setzen, bevor Sie einen lang laufenden Aufruf tätigen, wenn solche Objekte von der Anwendung nicht benötigt werden. Wenn Sie in Ihrer Anwendung kein statisches Objekt oder andere Objekte mehr benötigen, sollten Sie es auf null setzen, bevor Sie einen lang laufenden Aufruf tätigen. Sie sollten lokale Variablen nicht auf null setzen, da sie nicht benötigt werden. Die Laufzeit kann bestimmen, auf welches lokale Objekt in Ihrem Code nicht verwiesen oder nicht weiter verwendet wird. Sie müssen daher keine lokale Variable explizit auf null setzen.