Wann ist es akzeptabel, GC.Collect anzurufen?

166

Der allgemeine Rat ist, dass Sie nicht GC.Collectvon 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?

Brian Rasmussen
quelle
Mögliches Duplikat der Best Practice für das Erzwingen der
Speicherbereinigung

Antworten:

153

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.LowLatencyund GCLatencyMode.SustainedLowLatency. Wenn Sie einen dieser Modi aufrufen oder verlassen, wird empfohlen, einen vollständigen GC mit zu erzwingen GC.Collect(2, GCCollectionMode.Forced).

Ab .NET 4.6 gibt es die GC.TryStartNoGCRegionMethode (zum Festlegen des schreibgeschützten Werts GCLatencyMode.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:

Jon Skeet
quelle
8
Laut MS-Quellcode, der GC.Collect (2) alle 850 ms aufruft, ist das in Ordnung. Glaubst du nicht? Dann sehen Sie einfach PresentationCore.dll, MS.Internal.MemoryPressure.ProcessAdd (). Ich habe derzeit eine Bildverarbeitungs-App (kleine Bilder, nichts mit echtem Speicherdruck), bei der das Aufrufen von GC.Collect (2) länger als 850 ms dauert und die gesamte App dadurch eingefroren wird (App verbringt 99,7% der Zeit in GC).
springy76
36
@ springy76: Von Microsoft an einem Ort erledigt zu werden bedeutet nicht, dass es von denjenigen, die Ratschläge von Microsoft geben, als eine gute Sache angesehen wird ...
Jon Skeet
4
Ich mag dieses Beispiel nicht. Was macht es nach dem Schließen der Form? Ein gutes Beispiel, das ich sehe, ist nach dem Laden der Spielebene auf XBox oder WindowsPhone. Auf diesen Plattformen wird GC ausgeführt, nachdem 1 MB oder so etwas zugewiesen wurde. Es ist also gut, während des Ladens des Levels (während ein Begrüßungsbildschirm angezeigt wird) so viel wie möglich zuzuweisen und dann GC.Collect auszuführen, um zu versuchen, Sammlungen während des Spiels zu vermeiden.
Piotr Perak
8
@Peri: Der Sinn des Abschlusses nach dem Schließen des Formulars besteht darin, dass Sie gerade eine Reihe von Objekten (Steuerelemente, die von Ihnen angezeigten Daten) für die Speicherbereinigung in Frage gestellt haben. Wenn Sie also anrufen, teilen Sie dem Speicherbereiniger im GC.CollectGrunde mit, dass Sie ihn kennen zur Abwechslung besser als es. Warum magst du das Beispiel nicht?
Jon Skeet
6
@SHCJ: 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.
Jon Skeet
50

Ich benutze GC.Collectnur, wenn ich grobe Performance- / Profiler-Testgeräte schreibe. dh ich muss zwei (oder mehr) Codeblöcke testen - so etwas wie:

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestA(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestB(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
...

Also das TestA()und TestB()laufen mit so ähnlichem Zustand wie möglich - dh TestB()wird nicht gehämmert, nur weil TestAes sehr nahe am Kipppunkt gelassen wurde.

Ein klassisches Beispiel wäre eine einfache Konsolen-Exe (eine MainMethode, die zum Beispiel hier veröffentlicht werden kann), die den Unterschied zwischen der Verkettung von Schleifenzeichenfolgen und zeigt StringBuilder.

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

Marc Gravell
quelle
1
Und ich füge wahrscheinlich auch "WaitForPendingFinalizers" (oder was auch immer es ist) in diesem Fall hinzu ;-p
Marc Gravell
29

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.

  • Erhält eine Liste der Dateinamen in der Befehlszeile
  • Verarbeitet eine einzelne Datei und schreibt das Ergebnis in eine Ergebnisdatei.
  • Erstellt während der Verarbeitung der Datei viele miteinander verknüpfte Objekte, die erst nach Abschluss der Verarbeitung der Datei erfasst werden können (z. B. ein Analysebaum).
  • Behält den Übereinstimmungsstatus zwischen den verarbeiteten Dateien nicht bei .

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 würde nur in Betracht ziehen, eine Sammlung zu erzwingen, wenn ich weiß, dass in letzter Zeit viele Objekte erstellt wurden und derzeit nur auf sehr wenige Objekte verwiesen wird.

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 "

Ian Ringrose
quelle
19

Ein Fall ist, wenn Sie versuchen, Unit-Test-Code zu erstellen, der WeakReference verwendet .

Brian
quelle
11

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:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

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.

Paul Ruane
quelle
Ich habe die Sammlung mit zwei Durchgängen jetzt an einigen Stellen gesehen, aber nachdem ich die Passage in der MSDN-Dokumentation für GC.WaitForPendingFinalizers gelesen habe , die besagt: "Warten Sie, bis alle Finalizer abgeschlossen sind, bevor Sie fortfahren. Ohne diesen Aufruf von GC.WaitForPendingFinalizers, Die folgende Worker-Schleife wird möglicherweise zur gleichen Zeit wie die Finalizer ausgeführt. Bei diesem Aufruf wird die Worker-Schleife erst ausgeführt, nachdem alle Finalizer aufgerufen wurden. " Ich bin nur ein bisschen paranoid. Kennen Sie eine endgültige Quelle für zwei Durchgänge?
jerhewet
1
@jerhewet: Der Schlüssel zum Verständnis, warum zwei Sammlungen erforderlich sind, besteht darin, zu verstehen, was mit Objekten mit Finalisierern geschieht. Leider habe ich nicht genau das, wonach Sie fragen, aber ich habe diesen Artikel und diese Frage auf SO gelesen .
Paul Ruane
10

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.

Joel Coehoorn
quelle
8

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.

Ethos
quelle
7

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?

M4N
quelle
3
War schon da. Ich versuche nicht, Ausreden für etwas zu finden, das Sie nicht tun sollten, aber ich würde gerne wissen, ob es bestimmte Fälle gibt, in denen dies akzeptabel wäre.
Brian Rasmussen
5

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:

GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()

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 .

garthhh
quelle
Ja, ich bin darauf gestoßen, als .net auf Excel zugegriffen hat, was auch über COM-Objekte funktioniert. Es ist wichtig zu beachten, dass dies im DEBUG-Modus nicht gut funktioniert, da die GC-Operationen dort begrenzt sind. Es funktioniert wie beabsichtigt nur im RELEASE-Modus. relevanter Link: stackoverflow.com/questions/17130382/…
Blechdose
5

Ich habe einige Leistungstests für Array und Liste durchgeführt:

private static int count = 100000000;
private static List<int> GetSomeNumbers_List_int()
{
    var lstNumbers = new List<int>();
    for(var i = 1; i <= count; i++)
    {
        lstNumbers.Add(i);
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Array()
{
    var lstNumbers = new int[count];
    for (var i = 1; i <= count; i++)
    {
        lstNumbers[i-1] = i + 1;
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Enumerable_Range()
{
    return  Enumerable.Range(1, count).ToArray();
}

static void performance_100_Million()
{
    var sw = new Stopwatch();

    sw.Start();
    var numbers1 = GetSomeNumbers_List_int();
    sw.Stop();
    //numbers1 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"List<int>\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
    var numbers2 = GetSomeNumbers_Array();
    sw.Stop();
    //numbers2 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"int[]\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
//getting System.OutOfMemoryException in GetSomeNumbers_Enumerable_Range method
    var numbers3 = GetSomeNumbers_Enumerable_Range();
    sw.Stop();
    //numbers3 = null;
    //GC.Collect();

    Console.WriteLine(String.Format("\"int[]\" Enumerable.Range took {0} milliseconds", sw.ElapsedMilliseconds));
}

und ich habe OutOfMemoryExceptionin GetSomeNumbers_Enumerable_Range Methode die einzige Problemumgehung ist die Freigabe des Speichers durch:

numbers = null;
GC.Collect();
Daniel B.
quelle
Warum abstimmen? Meine Antwort ist ein Beispiel, das zeigt, wann man GC anruft. Haben Sie einen besseren Vorschlag? Sie können gerne präsentieren.
Daniel B
4

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

casperOne
quelle
3

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:

WeakReference w = CodeThatShouldNotMemoryLeak();
Assert.IsTrue(w.IsAlive);
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsFalse(w.IsAlive);

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.

ChaseMedallion
quelle
2

Die kurze Antwort lautet: niemals!

BankZ
quelle
9
Nicht einmal in dieser Situation ?
Roman Starkov
2
using(var stream = new MemoryStream())
{
   bitmap.Save(stream, ImageFormat.Png);
   techObject.Last().Image = Image.FromStream(stream);
   bitmap.Dispose();

   // Without this code, I had an OutOfMemory exception.
   GC.Collect();
   GC.WaitForPendingFinalizers();
   //
}
Denis
quelle
2

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.

Carl Looper
quelle
2

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":

public static TResult ExecuteOOMAware<T1, T2, TResult>(Func<T1,T2 ,TResult> func, T1 a1, T2 a2)
{

    int oomCounter = 0;
    int maxOOMRetries = 10;
    do
    {
        try
        {
            return func(a1, a2);
        }
        catch (OutOfMemoryException)
        {
            oomCounter++;
            if (maxOOMRetries > 10)
            {
                throw;
            }
            else
            {
                Log.Info("OutOfMemory-Exception caught, Trying to fix. Counter: " + oomCounter.ToString());
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(oomCounter * 10));
                GC.Collect();
            }
        }
    } while (oomCounter < maxOOMRetries);

    // never gets hitted.
    return default(TResult);
}

(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.)

Thomas Haller
quelle
Eine Komponente sollte nicht aufrufen GC.Collect. Da es eine anwendungsweite Wirkung hat, sollte dies nur die Anwendung tun (wenn überhaupt).
CodesInChaos
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.
G. Stoynev
2

Sie sollten versuchen, die Verwendung von GC.Collect () zu vermeiden, da dies sehr teuer ist. Hier ist ein Beispiel:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet.Remove(RecordSet[0]);

        }
        GC.Collect(); // AVOID
    }

TESTERGEBNIS: CPU-NUTZUNG 12%

Wenn Sie dies ändern:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet[0].Dispose(); //  Bitmap destroyed!
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet[0].Dispose(); //  Bitmap destroyed!
            RecordSet.Remove(RecordSet[0]);

        }
        //GC.Collect();
    }

TESTERGEBNIS: CPU-NUTZUNG 2-3%

mtekeli
quelle
1

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 :

try
{
    if (port != null)
        port.Close(); //this will throw an exception if the port was unplugged
}
catch (Exception ex) //of type 'System.IO.IOException'
{
    System.GC.Collect();
    System.GC.WaitForPendingFinalizers();
}

port = null;
Jay Tennant
quelle
0

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.

Chris S.
quelle
0

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.

harry4516
quelle
0

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

Max CHien
quelle
0

Wenn Sie viele neue System.Drawing.BitmapObjekte 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. Ab GC.Collect()und zu anzurufen (nicht zu oft!) Scheint dieses Problem zu lösen.

Nacht
quelle