Der allgemeine Rat ist, dass Sie nicht GC.Collect
von Ihrem Code aus aufrufen sollten , aber was sind die Ausnahmen von dieser Regel?
Ich kann mir nur einige sehr spezifische Fälle vorstellen, in denen es sinnvoll sein kann, eine Speicherbereinigung zu erzwingen.
Ein Beispiel, das mir in den Sinn kommt, ist ein Dienst, der in regelmäßigen Abständen aufwacht, eine Aufgabe ausführt und dann lange schläft. In diesem Fall kann es eine gute Idee sein, eine Erfassung zu erzwingen, um zu verhindern, dass der Prozess, der in Kürze inaktiv sein wird, mehr Speicher als erforderlich benötigt.
Gibt es andere Fälle, in denen ein Anruf akzeptabel ist GC.Collect
?
c#
.net
garbage-collection
Brian Rasmussen
quelle
quelle
Antworten:
Wenn Sie guten Grund zu der Annahme haben, dass eine bedeutende Anzahl von Objekten - insbesondere solche, von denen Sie vermuten, dass sie in den Generationen 1 und 2 vorliegen - jetzt für die Speicherbereinigung in Frage kommen, ist dies jetzt ein angemessener Zeitpunkt für die Erfassung im Hinblick auf den geringen Leistungseinbruch .
Ein gutes Beispiel hierfür ist, wenn Sie gerade ein großes Formular geschlossen haben. Sie wissen, dass jetzt alle Steuerelemente der Benutzeroberfläche durch Müll gesammelt werden können, und eine sehr kurze Pause beim Schließen des Formulars wird für den Benutzer wahrscheinlich nicht erkennbar sein.
UPDATE 2.7.2018
Ab .NET 4.5 gibt es
GCLatencyMode.LowLatency
undGCLatencyMode.SustainedLowLatency
. Wenn Sie einen dieser Modi aufrufen oder verlassen, wird empfohlen, einen vollständigen GC mit zu erzwingenGC.Collect(2, GCCollectionMode.Forced)
.Ab .NET 4.6 gibt es die
GC.TryStartNoGCRegion
Methode (zum Festlegen des schreibgeschützten WertsGCLatencyMode.NoGCRegion
). Dies kann selbst eine vollständig blockierende Garbage Collection durchführen, um genügend Speicher freizugeben. Da wir GC jedoch für einen bestimmten Zeitraum nicht zulassen, ist es meiner Meinung nach auch eine gute Idee, vorher und nachher eine vollständige GC durchzuführen.Quelle: Microsoft-Ingenieur Ben Watson: Schreiben von leistungsstarkem .NET-Code , 2. Aufl. 2018.
Sehen:
quelle
GC.Collect
Grunde mit, dass Sie ihn kennen zur Abwechslung besser als es. Warum magst du das Beispiel nicht?GC.Collect()
fordert den GC auf, eine vollständige Erfassung durchzuführen . Wenn Sie wissen, dass Sie gerade viele zuvor langlebige Objekte für die Speicherbereinigung in Frage gestellt haben und Sie der Meinung sind, dass der Benutzer jetzt weniger wahrscheinlich eine leichte Pause bemerkt als später, ist es durchaus vernünftig zu glauben, dass dies jetzt besser ist Zeit, eine Sammlung aufzufordern, als sie später passieren zu lassen.Ich benutze
GC.Collect
nur, wenn ich grobe Performance- / Profiler-Testgeräte schreibe. dh ich muss zwei (oder mehr) Codeblöcke testen - so etwas wie:Also das
TestA()
undTestB()
laufen mit so ähnlichem Zustand wie möglich - dhTestB()
wird nicht gehämmert, nur weilTestA
es sehr nahe am Kipppunkt gelassen wurde.Ein klassisches Beispiel wäre eine einfache Konsolen-Exe (eine
Main
Methode, die zum Beispiel hier veröffentlicht werden kann), die den Unterschied zwischen der Verkettung von Schleifenzeichenfolgen und zeigtStringBuilder
.Wenn ich etwas Genaues brauche, dann sind dies zwei völlig unabhängige Tests - aber oft reicht dies aus, wenn wir den GC während der Tests nur minimieren (oder normalisieren) möchten, um ein grobes Gefühl für das Verhalten zu bekommen.
Während des Produktionscodes? Ich habe es noch nicht benutzt ;-p
quelle
In den meisten Fällen wird empfohlen, keine Speicherbereinigung zu erzwingen. (Jedes System, an dem ich gearbeitet habe, hatte Garbage Collections erzwungen, Probleme unterstrichen, die bei einer Lösung die Notwendigkeit des Erzwingens der Garbage Collection beseitigt und das System erheblich beschleunigt hätten.)
Es gibt einige Fälle, in denen 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
Ein Fall ist, wenn Sie versuchen, Unit-Test-Code zu erstellen, der WeakReference verwendet .
quelle
In großen 24 / 7- oder 24/6-Systemen - Systemen, die auf Nachrichten, RPC-Anforderungen reagieren oder eine Datenbank oder einen Prozess kontinuierlich abfragen - ist es hilfreich, eine Möglichkeit zu haben, Speicherlecks zu identifizieren. Aus diesem Grund neige ich dazu, der Anwendung einen Mechanismus hinzuzufügen, um die Verarbeitung vorübergehend anzuhalten und dann eine vollständige Speicherbereinigung durchzuführen. Dies versetzt das System in einen Ruhezustand, in dem der verbleibende Speicher entweder ein recht langlebiger Speicher ist (Caches, Konfiguration usw.) oder "durchgesickert" ist (Objekte, von denen nicht erwartet wird oder gewünscht wird, dass sie gerootet werden, aber tatsächlich verwurzelt sind).
Dieser Mechanismus erleichtert die Profilierung der Speichernutzung erheblich, da die Berichte nicht durch Rauschen aus der aktiven Verarbeitung getrübt werden.
Um sicherzugehen, dass Sie den gesamten Müll erhalten, müssen Sie zwei Sammlungen durchführen:
Da die erste Sammlung dazu führt, dass alle Objekte mit Finalisierern finalisiert werden (aber nicht wirklich Müll sammeln diese Objekte). Der zweite GC sammelt diese finalisierten Objekte im Müll.
quelle
Sie können GC.Collect () aufrufen, wenn Sie etwas über die Art der App wissen, die der Garbage Collector nicht kennt. Es ist verlockend zu glauben, dass dies als Autor sehr wahrscheinlich ist. Die Wahrheit ist jedoch, dass der GC ein ziemlich gut geschriebenes und getestetes Expertensystem darstellt, und es ist selten, dass Sie etwas über die Codepfade auf niedriger Ebene wissen, die er nicht kennt.
Das beste Beispiel, an das ich denken kann, wo Sie möglicherweise zusätzliche Informationen haben, ist eine App, die zwischen Leerlaufzeiten und stark ausgelasteten Zeiten wechselt. Sie möchten die bestmögliche Leistung für die Stoßzeiten erzielen und möchten daher die Leerlaufzeit für einige Aufräumarbeiten nutzen.
Meistens ist der GC jedoch trotzdem klug genug, dies zu tun.
quelle
Als Speicherfragmentierungslösung. Beim Schreiben vieler Daten in einen Speicherstrom (Lesen aus einem Netzwerkstrom) gingen mir Speicherausnahmen aus. Die Daten wurden in 8K-Blöcken geschrieben. Nach Erreichen von 128 MB gab es eine Ausnahme, obwohl viel Speicher verfügbar war (aber fragmentiert war). Das Aufrufen von GC.Collect () hat das Problem behoben. Nach dem Fix konnte ich über 1G verarbeiten.
quelle
Schauen Sie sich diesen Artikel von Rico Mariani an. Er gibt zwei Regeln an, wann GC.Collect aufgerufen werden soll (Regel 1 lautet: "Nicht"):
Wann soll GC.Collect () aufgerufen werden?
quelle
Ein Fall, in dem es fast notwendig ist, GC.Collect () aufzurufen, ist die Automatisierung von Microsoft Office über Interop. COM-Objekte für Office werden nicht automatisch freigegeben und können dazu führen, dass Instanzen des Office-Produkts sehr viel Speicherplatz beanspruchen. Ich bin mir nicht sicher, ob dies ein Problem ist oder beabsichtigt. Es gibt viele Beiträge zu diesem Thema im Internet, damit ich nicht zu sehr ins Detail gehe.
Bei der Programmierung mit Interop sollte jedes einzelne COM-Objekt manuell freigegeben werden, normalerweise mithilfe von Marshal.ReleseComObject (). Darüber hinaus kann das manuelle Aufrufen der Garbage Collection dazu beitragen, ein wenig "aufzuräumen". Das Aufrufen des folgenden Codes, wenn Sie mit Interop-Objekten fertig sind, scheint ziemlich hilfreich zu sein:
Nach meiner persönlichen Erfahrung reduziert die Verwendung einer Kombination aus ReleaseComObject und dem manuellen Aufrufen der Garbage Collection die Speichernutzung von Office-Produkten, insbesondere Excel, erheblich .
quelle
Ich habe einige Leistungstests für Array und Liste durchgeführt:
und ich habe
OutOfMemoryException
in GetSomeNumbers_Enumerable_Range Methode die einzige Problemumgehung ist die Freigabe des Speichers durch:quelle
In Ihrem Beispiel denke ich, dass das Aufrufen von GC.Collect nicht das Problem ist, sondern ein Designproblem.
Wenn Sie in regelmäßigen Abständen aufwachen (festgelegte Zeiten), sollte Ihr Programm für eine einzelne Ausführung erstellt werden (führen Sie die Aufgabe einmal aus) und dann beendet. Anschließend richten Sie das Programm als geplante Aufgabe ein, die in den geplanten Intervallen ausgeführt werden soll.
Auf diese Weise müssen Sie sich nicht darum kümmern, GC.Collect anzurufen (was Sie selten tun sollten nie tun sollten).
Davon abgesehen hat Rico Mariani einen großartigen Blog-Beitrag zu diesem Thema, den Sie hier finden:
http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx
quelle
Ein nützlicher Ort zum Aufrufen von GC.Collect () ist ein Komponententest, wenn Sie überprüfen möchten, ob Sie keinen Speicherverlust verursachen (z. B. wenn Sie etwas mit WeakReferences oder ConditionalWeakTable, dynamisch generiertem Code usw. tun).
Zum Beispiel habe ich ein paar Tests wie:
Es könnte argumentiert werden, dass die Verwendung von WeakReferences an und für sich ein Problem darstellt. Wenn Sie jedoch ein System erstellen, das auf einem solchen Verhalten basiert, ist der Aufruf von GC.Collect () eine gute Möglichkeit, diesen Code zu überprüfen.
quelle
Der Blogeintrag von Scott Holden, wann GC.Collect aufgerufen werden soll (und wann nicht), ist spezifisch für das .NET Compact Framework , die Regeln gelten jedoch im Allgemeinen für alle verwalteten Entwicklungen.
quelle
Die kurze Antwort lautet: niemals!
quelle
quelle
Es gibt Situationen, in denen es besser sicher als leid ist.
Hier ist eine Situation.
Es ist möglich, ein nicht verwaltetes zu verfassen DLL in C # mithilfe von IL-Umschreibungen zu erstellen (da dies in bestimmten Situationen erforderlich ist).
Angenommen, die DLL erstellt beispielsweise ein Array von Bytes auf Klassenebene, da viele der exportierten Funktionen Zugriff auf diese benötigen. Was passiert, wenn die DLL entladen wird? Wird der Garbage Collector an diesem Punkt automatisch aufgerufen? Ich weiß es nicht, aber es wird nicht verwaltet DLL handelt, ist es durchaus möglich, dass der GC nicht aufgerufen wird. Und es wäre ein großes Problem, wenn es nicht aufgerufen würde. Wenn die DLL entladen wird, ist dies auch der Garbage Collector. Wer wird also für das Sammeln von möglichem Müll verantwortlich sein und wie würden sie das tun? Verwenden Sie besser den Garbage Collector von C #. Haben Sie eine Bereinigungsfunktion (für den DLL-Client verfügbar), bei der die Variablen auf Klassenebene auf null gesetzt und der Garbage Collector aufgerufen werden.
Sicher ist sicher.
quelle
Ich bin mir immer noch ziemlich unsicher. Ich arbeite seit 7 Jahren an einem Anwendungsserver. Unsere größeren Installationen verwenden 24 GB RAM. Es ist hochgradig Multithreaded und ALLE Aufrufe für GC.Collect () stießen auf wirklich schreckliche Leistungsprobleme.
Viele Komponenten von Drittanbietern verwendeten GC.Collect (), als sie es für klug hielten, dies jetzt zu tun. Eine einfache Reihe von Excel-Berichten blockierte den App Server mehrmals pro Minute für alle Threads.
Wir mussten alle Komponenten von Drittanbietern umgestalten, um die GC.Collect () -Aufrufe zu entfernen, und danach funktionierten alle einwandfrei.
Aber ich verwende Server auch unter Win32, und hier habe ich angefangen, GC.Collect () stark zu nutzen, nachdem ich eine OutOfMemoryException erhalten habe.
Aber ich bin mir auch ziemlich unsicher, weil ich oft bemerkt habe, dass es einfach funktioniert hat, wenn ich ein OOM auf 32 Bit bekomme und erneut versuche, dieselbe Operation erneut auszuführen, ohne GC.Collect () aufzurufen.
Eine Sache, die ich mich frage, ist die OOM-Ausnahme selbst ... Wenn ich das .Net Framework geschrieben hätte und keinen Speicherblock zuweisen kann, würde ich GC.Collect () verwenden, Speicher defragmentieren (??), es erneut versuchen , und wenn ich immer noch keinen freien Speicherblock finden kann, würde ich die OOM-Ausnahme auslösen.
Oder machen Sie dieses Verhalten aufgrund der Nachteile des Leistungsproblems mit GC.Collect zumindest zu einer konfigurierbaren Option.
Jetzt habe ich viel Code wie diesen in meiner App, um das Problem zu "lösen":
(Beachten Sie, dass das Thread.Sleep () -Verhalten ein wirklich App-spezifisches Verhalten ist, da wir einen ORM-Caching-Dienst ausführen und der Dienst einige Zeit benötigt, um alle zwischengespeicherten Objekte freizugeben, wenn der RAM einige vordefinierte Werte überschreitet einige Sekunden beim ersten Mal und hat die Wartezeit bei jedem Auftreten von OOM erhöht.)
quelle
GC.Collect
. Da es eine anwendungsweite Wirkung hat, sollte dies nur die Anwendung tun (wenn überhaupt).If i would have written the .Net Framework, and i can't alloc a memory block, i would use GC.Collect(),
- Ich denke, sie tun dies bereits. - Ich habe Anzeichen dafür gesehen, dass einer der internen GC-Auslöser bestimmte Fehler bei der Zuweisung von Speicher sind.Sie sollten versuchen, die Verwendung von GC.Collect () zu vermeiden, da dies sehr teuer ist. Hier ist ein Beispiel:
TESTERGEBNIS: CPU-NUTZUNG 12%
Wenn Sie dies ändern:
TESTERGEBNIS: CPU-NUTZUNG 2-3%
quelle
Ein weiterer Grund ist, wenn Sie einen SerialPort an einem USB-COM-Anschluss geöffnet haben und das USB-Gerät dann vom Stromnetz getrennt wird. Da der SerialPort geöffnet wurde, enthält die Ressource einen Verweis auf den zuvor verbundenen Port in der Systemregistrierung. Die Registrierung des Systems enthält dann veraltete Daten , sodass die Liste der verfügbaren Ports falsch ist. Daher muss der Port geschlossen sein.
Wenn Sie SerialPort.Close () für den Port aufrufen, wird Dispose () für das Objekt aufgerufen. Es bleibt jedoch im Speicher, bis die Garbage Collection tatsächlich ausgeführt wird. Dadurch bleibt die Registrierung veraltet, bis der Garbage Collector beschließt, die Ressource freizugeben.
Von https://stackoverflow.com/a/58810699/8685342 :
quelle
Dies ist für die Frage nicht so relevant, aber für XSLT-Transformationen in .NET (XSLCompiledTranform) haben Sie möglicherweise keine Wahl. Ein weiterer Kandidat ist das MSHTML-Steuerelement.
quelle
Wenn Sie eine .net-Version unter 4.5 verwenden, kann eine manuelle Erfassung unvermeidlich sein (insbesondere, wenn Sie mit vielen "großen Objekten" arbeiten).
Dieser Link beschreibt warum:
https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/
quelle
Ein guter Grund für den Aufruf von GC sind kleine ARM-Computer mit wenig Speicher wie der Raspberry PI (mit Mono). Wenn nicht zugewiesene Speicherfragmente zu viel System-RAM verbrauchen, kann das Linux-Betriebssystem instabil werden. Ich habe eine Anwendung, in der ich GC jede Sekunde (!) Aufrufen muss, um Speicherüberlaufprobleme zu beseitigen.
Eine andere gute Lösung besteht darin, Objekte zu entsorgen, wenn sie nicht mehr benötigt werden. Leider ist dies in vielen Fällen nicht so einfach.
quelle
Da es Small Object Heap (SOH) und Large Object Heap (LOH) gibt
Wir können GC.Collect () aufrufen, um das Referenzierungsobjekt in SOP zu löschen und das lebende Objekt in die nächste Generation zu verschieben.
In .net4.5 können wir LOH auch mithilfe des großen Objektverdichtungsmodus komprimieren
quelle
Wenn Sie viele neue
System.Drawing.Bitmap
Objekte erstellen , werden diese vom Garbage Collector nicht gelöscht. Schließlich wird GDI + denken, dass Ihnen der Speicher ausgeht, und eine Ausnahme "Der Parameter ist ungültig" auslösen. AbGC.Collect()
und zu anzurufen (nicht zu oft!) Scheint dieses Problem zu lösen.quelle