Die beste Vorgehensweise besteht darin, keine Speicherbereinigung zu erzwingen.
Laut MSDN:
"Es ist möglich, die Speicherbereinigung durch Aufrufen von Collect zu erzwingen. In den meisten Fällen sollte dies jedoch vermieden werden, da dies zu Leistungsproblemen führen kann."
Wenn Sie Ihren Code jedoch zuverlässig testen können, um zu bestätigen, dass der Aufruf von Collect () keine negativen Auswirkungen hat, fahren Sie fort ...
Stellen Sie einfach sicher, dass Objekte bereinigt werden, wenn Sie sie nicht mehr benötigen. Wenn Sie benutzerdefinierte Objekte haben, verwenden Sie die "using-Anweisung" und die IDisposable-Schnittstelle.
Dieser Link enthält einige gute praktische Ratschläge zum Freigeben von Speicher / Speicherbereinigung usw.:
http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
TargetOfInvocationNullException
.Betrachten Sie es so - ist es effizienter, den Küchenmüll wegzuwerfen, wenn der Mülleimer 10% beträgt, oder ihn vor dem Herausnehmen auffüllen zu lassen?
Wenn Sie es nicht auffüllen lassen, verschwenden Sie Ihre Zeit damit, von und zur Mülltonne draußen zu gehen. Dies ist analog zu dem, was passiert, wenn der GC-Thread ausgeführt wird. Alle verwalteten Threads werden angehalten, während er ausgeführt wird. Und wenn ich mich nicht irre, kann der GC-Thread von mehreren AppDomains gemeinsam genutzt werden, sodass die Speicherbereinigung alle betrifft.
Natürlich kann es vorkommen, dass Sie dem Müll bald nichts mehr hinzufügen - sagen wir, wenn Sie Urlaub machen. Dann wäre es eine gute Idee, den Müll wegzuwerfen, bevor Sie ausgehen.
Dies könnte ein Mal sein, dass das Erzwingen eines GC hilfreich sein kann. Wenn Ihr Programm inaktiv ist, wird der verwendete Speicher nicht durch Speicherbereinigung erfasst, da keine Zuordnungen vorhanden sind.
quelle
In den meisten Fällen wird empfohlen, keine Speicherbereinigung zu erzwingen. (Jedes System, an dem ich gearbeitet habe, hatte die Speicherbereinigung erzwungen, Probleme unterstrichen, die bei einer Lösung die Notwendigkeit der Speicherbereinigung beseitigt hätten, und das System erheblich beschleunigt.)
Es gibt ein paar Fälle , wenn Sie mehr über die Speichernutzung wissen dann der Garbage Collector tut. Es ist unwahrscheinlich, dass dies in einer Mehrbenutzeranwendung oder einem Dienst der Fall ist, der auf mehr als eine Anfrage gleichzeitig reagiert.
Bei einigen Stapelverarbeitungen wissen Sie jedoch mehr als der GC. Betrachten Sie beispielsweise eine Anwendung, die.
Möglicherweise können Sie (nach sorgfältiger Prüfung) prüfen, ob Sie eine vollständige Speicherbereinigung erzwingen sollten, nachdem Sie jede Datei verarbeitet haben.
Ein anderer Fall ist ein Dienst, der alle paar Minuten aufwacht, um einige Elemente zu verarbeiten, und keinen Zustand beibehält, während er schläft . Dann kann es sich lohnen, kurz vor dem Schlafengehen eine vollständige Sammlung zu erzwingen .
Ich hätte lieber eine Garbage Collection-API, wenn ich ihr Hinweise zu solchen Dingen geben könnte, ohne selbst einen GC erzwingen zu müssen.
Siehe auch " Rico Marianis Performance-Leckerbissen "
quelle
Ich denke, das Beispiel von Rico Mariani war gut: Es kann angebracht sein, einen GC auszulösen, wenn sich der Status der Anwendung erheblich ändert. In einem Dokumenteditor kann es beispielsweise in Ordnung sein, einen GC auszulösen, wenn ein Dokument geschlossen wird.
quelle
Es gibt nur wenige allgemeine Richtlinien für die Programmierung, die absolut sind. In der Hälfte der Fälle, in denen jemand sagt, dass Sie es falsch machen, spricht er nur eine bestimmte Menge an Dogmen aus. In C war es früher Angst vor Dingen wie selbstmodifizierendem Code oder Threads, in GC-Sprachen erzwingt es den GC oder verhindert alternativ, dass der GC ausgeführt wird.
Wie bei den meisten Richtlinien und guten Faustregeln (und guten Entwurfspraktiken) gibt es seltene Fälle, in denen es sinnvoll ist, die etablierte Norm zu umgehen. Sie müssen sehr sicher sein, dass Sie den Fall verstehen, dass Ihr Fall wirklich die Aufhebung der gängigen Praxis erfordert und dass Sie die Risiken und Nebenwirkungen verstehen, die Sie verursachen können. Aber es gibt solche Fälle.
Programmierprobleme sind sehr unterschiedlich und erfordern einen flexiblen Ansatz. Ich habe Fälle gesehen, in denen es sinnvoll ist, GC in von Müll gesammelten Sprachen zu blockieren, und Orte, an denen es sinnvoll ist, sie auszulösen, anstatt darauf zu warten, dass sie auf natürliche Weise auftritt. In 95% der Fälle wäre beides ein Wegweiser dafür, dass das Problem nicht richtig angegangen wurde. Aber 1 Mal in 20 gibt es wahrscheinlich einen gültigen Fall dafür.
quelle
Ich habe gelernt, nicht zu versuchen, die Garbage Collection zu überlisten. Trotzdem bleibe ich bei der Verwendung von
using
Schlüsselwörtern, wenn es um nicht verwaltete Ressourcen wie Datei-E / A oder Datenbankverbindungen geht.quelle
Ich bin mir nicht sicher, ob es eine bewährte Methode ist, aber wenn ich mit großen Mengen von Bildern in einer Schleife arbeite (dh viele Grafik- / Bild- / Bitmap-Objekte erstellen und entsorgen), lasse ich das GC.Collect regelmäßig.
Ich glaube, ich habe irgendwo gelesen, dass der GC nur ausgeführt wird, wenn das Programm (meistens) im Leerlauf ist und nicht mitten in einer intensiven Schleife, so dass dies wie ein Bereich aussehen könnte, in dem manueller GC sinnvoll sein könnte.
quelle
Ein Fall, auf den ich kürzlich gestoßen bin und für den manuelle Aufrufe erforderlich waren,
GC.Collect()
war die Arbeit mit großen C ++ - Objekten, die in winzige verwaltete C ++ - Objekte eingeschlossen waren, auf die wiederum über C # zugegriffen wurde.Der Garbage Collector wurde nie aufgerufen, da die Menge des verwendeten verwalteten Speichers vernachlässigbar war, aber die Menge des verwendeten nicht verwalteten Speichers war riesig. Das manuelle Aufrufen
Dispose()
der Objekte würde erfordern, dass ich selbst verfolge, wann Objekte nicht mehr benötigt werden, während das AufrufenGC.Collect()
alle Objekte bereinigt, auf die nicht mehr verwiesen wird .....quelle
GC.AddMemoryPressure (ApproximateSizeOfUnmanagedResource)
den Konstruktor und späterGC.RemoveMemoryPressure(addedSize)
den Finalizer aufzurufen . Auf diese Weise wird der Garbage Collector automatisch ausgeführt, wobei die Größe der nicht verwalteten Strukturen berücksichtigt wird, die gesammelt werden könnten. stackoverflow.com/questions/1149181/…Ich denke, Sie haben bereits die Best Practice aufgelistet, und das ist NICHT zu verwenden, es sei denn, WIRKLICH notwendig. Ich würde dringend empfehlen, Ihren Code genauer zu betrachten und bei Bedarf möglicherweise Profiling-Tools zu verwenden, um diese Fragen zuerst zu beantworten.
quelle
Angenommen, Ihr Programm weist keinen Speicherverlust auf, Objekte sammeln sich an und können in Gen 0 nicht GC-bearbeitet werden, weil: 1) Sie für lange Zeit referenziert werden, also gehen Sie zu Gen1 & Gen2; 2) Es handelt sich um große Objekte (> 80 KB). Gehen Sie also zu LOH (Large Object Heap). Und LOH komprimiert nicht wie in Gen0, Gen1 und Gen2.
Überprüfen Sie den Leistungsindikator von ".NET Memory". Sie können sehen, dass das 1) Problem wirklich kein Problem ist. Im Allgemeinen löst jede 10 Gen0 GC 1 Gen1 GC aus, und jede 10 Gen1 GC löst 1 Gen2 GC aus. Theoretisch können GC1 und GC2 niemals GC-bearbeitet werden, wenn kein Druck auf GC0 ausgeübt wird (wenn die Programmspeicherauslastung wirklich verdrahtet ist). Das passiert mir nie.
Bei Problem 2) können Sie den Leistungsindikator ".NET Memory" überprüfen, um festzustellen, ob LOH aufgebläht ist. Wenn es sich wirklich um ein Problem handelt, können Sie möglicherweise einen Pool mit großen Objekten erstellen, wie in diesem Blog unter http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx vorgeschlagen .
quelle
Große Objekte werden auf LOH (Large Object Heap) zugewiesen, nicht auf Gen 0. Wenn Sie sagen, dass sie mit Gen 0 nicht durch Müll gesammelt werden, haben Sie Recht. Ich glaube, sie werden nur gesammelt, wenn der gesamte GC-Zyklus (Generationen 0, 1 und 2) stattfindet.
Abgesehen davon glaube ich, dass GC auf der anderen Seite den Speicher aggressiver anpasst und sammelt, wenn Sie mit großen Objekten arbeiten und der Speicherdruck steigt.
Es ist schwer zu sagen, ob und unter welchen Umständen gesammelt werden soll oder nicht. Ich habe GC.Collect () ausgeführt, nachdem ich Dialogfenster / Formulare mit zahlreichen Steuerelementen usw. entsorgt hatte (weil das Formular und seine Steuerelemente zu dem Zeitpunkt in Gen 2 landen, weil viele Instanzen von Geschäftsobjekten erstellt / viele Daten geladen wurden - nein große Objekte offensichtlich), bemerkte aber auf lange Sicht keine positiven oder negativen Auswirkungen.
quelle
Ich möchte Folgendes hinzufügen: Das Aufrufen von GC.Collect () (+ WaitForPendingFinalizers ()) ist ein Teil der Geschichte. Wie von anderen zu Recht erwähnt, ist GC.COllect () eine nicht deterministische Sammlung und liegt im Ermessen des GC selbst (CLR). Selbst wenn Sie WaitForPendingFinalizers einen Aufruf hinzufügen, ist dieser möglicherweise nicht deterministisch. Nehmen Sie den Code von diesem msdn- Link und führen Sie den Code mit der Objektschleifeniteration als 1 oder 2 aus. Sie werden feststellen, was nicht deterministisch bedeutet (setzen Sie einen Bruchpunkt im Destruktor des Objekts). Genau genommen wird der Destruktor nicht aufgerufen, wenn nur 1 (oder 2) verbleibende Objekte von Wait .. () vorhanden waren. [Zitieranforderung]
Wenn Ihr Code nicht verwaltete Ressourcen enthält (z. B. externe Dateihandles), müssen Sie Destruktoren (oder Finalizer) implementieren.
Hier ist ein interessantes Beispiel:
Hinweis : Wenn Sie das obige Beispiel bereits von MSDN aus ausprobiert haben, wird der folgende Code die Luft reinigen.
Ich schlage vor, zuerst zu analysieren, wie die Ausgabe aussehen könnte, dann auszuführen und dann den folgenden Grund zu lesen:
{Der Destruktor wird nur implizit aufgerufen, wenn das Programm endet. } Um das Objekt deterministisch zu bereinigen, muss IDisposable implementiert und Dispose () explizit aufgerufen werden. Das ist die Essenz! :) :)
quelle
Wenn Sie GC Collect explizit auslösen, wird die Leistung Ihres Programms möglicherweise NICHT verbessert. Es ist durchaus möglich, es noch schlimmer zu machen.
Der .NET GC ist gut konzipiert und anpassungsfähig abgestimmt, was bedeutet, dass er den GC0 / 1/2-Schwellenwert entsprechend der "Gewohnheit" Ihrer Programmspeicherauslastung anpassen kann. So wird es nach einiger Zeit an Ihr Programm angepasst. Sobald Sie GC.Collect explizit aufrufen, werden die Schwellenwerte zurückgesetzt! Und das .NET muss Zeit aufwenden, um sich wieder an die "Gewohnheit" Ihres Programms anzupassen.
Mein Vorschlag ist immer, .NET GC zu vertrauen. Wenn Speicherprobleme auftreten, überprüfen Sie den Leistungsindikator ".NET Memory" und diagnostizieren Sie meinen eigenen Code.
quelle
Vorschlag: Implementieren Sie dies oder etwas anderes nicht, wenn Sie sich nicht sicher sind. Bewerten Sie erneut, wenn Fakten bekannt sind, und führen Sie dann vor / nach Leistungstests durch, um dies zu überprüfen.
quelle
IMHO, das ist ähnlich wie zu sagen: "Wenn Sie beweisen können, dass Ihr Programm in Zukunft keine Fehler mehr haben wird, dann fahren Sie fort ..."
In aller Ernsthaftigkeit ist das Erzwingen des GC zum Debuggen / Testen nützlich. Wenn Sie das Gefühl haben, dass Sie dies zu einem anderen Zeitpunkt tun müssen, irren Sie sich entweder oder Ihr Programm wurde falsch erstellt. In beiden Fällen erzwingt die Lösung nicht den GC ...
quelle