Skip to content

Beiträge

Garbage Collection-Typen in .Net Core

2. September 2019 • 4 Min. Lesezeit

Garbage Collection-Typen in .Net Core

Speicherverwaltung in modernen Sprachen ist oft ein nachträglicher Gedanke. Praktisch gesehen schreiben wir Software, ohne auch nur einen Gedanken an den Speicher zu verschwenden. Das dient uns gut, aber es gibt immer Ausnahmen…

In Kalifornien gibt es umfangreiche Finanzberichterstattungsanforderungen für Local Education Agencies (LEA), eine LEA kann ein Landkreis, ein Bezirk, eine Charter-Schule oder eine einzelne Schule sein. Die meisten LEAs erstellen ihre eigenen Finanzberichte, die normalerweise auf Excel basieren, es ist keine Überraschung, wenn jeder Bericht anders ist. Um dieses Problem zu lösen, beauftragte das California Board of Education Software zur Generierung von Finanzberichten.

Ich war Teil des Entwicklungsteams.

Mein erster Anlaufpunkt waren die Testprotokolle, Ed-Pros Protokolle deuteten auf hohe Speichernutzung hin, vielleicht gab es ein Speicherleck? Ein Ingenieur beobachtete, dass Ed-Pros Berechnungen eine große Menge kurzlebigen Speichers verwendeten. Wenn der Speicher nicht schnell bereinigt wurde, könnte es wie ein Speicherleck aussehen.

Ed-Pro basiert auf .Net Core, Microsofts plattformübergreifendem Framework. In .Net Core ist der Speicher in drei Kategorien unterteilt: Kurzlebig (Gen0), mittelfristig (Gen1) und langlebig (Gen2). Gen0 ist für kurzlebige Daten, die schnell aus dem Gültigkeitsbereich fallen, Gen1 ist für mittelfristig lebenden Speicher, der etwas länger bestehen bleibt, aber schließlich auch aus dem Gültigkeitsbereich fällt, und Gen2 ist langlebiger Speicher, der für die Lebensdauer der Anwendung bestehen kann. Gen0-Speicher wird ständig zurückgewonnen, Gen1 wird weniger häufig als Gen0 zurückgewonnen, und Gen2 wird noch weniger häufig als Gen1 zurückgewonnen.

Der einzige sichere Weg, die Speichernutzung von Ed-Pro zu verstehen, war eine Profilerstellung. Unten ist ein Screenshot mit dotMemory von JetBrains.

Wie vermutet fanden wir große Mengen an Gen0-Speicher (das Blaue), so viel, dass es schien, als könnte die Garbage Collection nicht mithalten. Eine Strategie zum Ausgleich einer großen Speichermenge führte dazu, dass die Garbage Collection zwischen der Erhöhung des Speicherplatzes (Hinzufügung von mehr Speicher für die Nutzung der Anwendung) und der Bereinigung oszillierte. Während der Bereinigungszyklen reagiert die Anwendung nicht.

Zunächst waren wir ratlos, ist es nicht der Zweck der GC, den Speicher sauber zu halten? Zwei Artikel waren entscheidend für unser Verständnis, wie Garbage Collection in .Net funktioniert: Mark Vinczes Artikel Troubleshooting high memory usage with ASP.Net Core on Kubernetes und Fundamentals of Garbage Collection von Microsoft. Beide sind großartige Lektüren und brachten Klarheit in die Speichernutzung in Ed-Pro.

Hier ist eine Zusammenfassung dessen, was wir gelernt haben: Es gibt zwei Arten von Garbage Collection in .Net: Server Garbage Collection und Workstation Garbage Collection.

Server Garbage Collection macht ein paar Annahmen: Erstens, dass ausreichend Speicher verfügbar ist, und zweitens, dass die Prozessoren Multi-Core und schnell sind. Beides kann zutreffen, aber wir leben in einer Welt von virtuellen Maschinen und Docker, wo es wahrscheinlicher ist, dass beide Annahmen falsch sind.

Server Garbage Collection lässt Speicher anwachsen, irgendwann macht sie eines von zwei Dingen: Sie erhöht entweder den Speicherplatz und lässt den Speicher wachsen oder sie gibt verwaisten Speicher frei. Wenn sie sich entscheidet, Speicher freizugeben, startet die Garbage Collection den Prozess in einem hochpriorisierten Thread. Der hochpriorisierte Thread hat eine höhere Priorität als die Anwendung; wenn die Maschine schnell ist, sollte die Bereinigung nicht bemerkt werden. Wenn sie es jedoch nicht ist, wird sie die Anwendung zum Stillstand bringen, bis die Bereinigung abgeschlossen ist.

Workstation Garbage Collection funktioniert anders. Sie läuft kontinuierlich und gewinnt Speicher in einem Thread mit derselben Priorität wie die Anwendung zurück. Das bedeutet, sie konkurriert auch um Ressourcen mit der Anwendung, was zu Anwendungsverlangsamung führen kann. Der Vorteil ist, dass die Speichernutzung der Anwendung ziemlich niedrig bleiben kann, hauptsächlich wenn sie große Mengen an Gen0 verwendet.

Standardmäßig führt .Net Core den Server Garbage Collection-Typ aus, wenn es einen Server erkennt, was bei unserer Anwendung der Fall war. Um den Workstation Garbage Collection-Typ auszuführen, fügen Sie das folgende Snippet zu Ihrer Projektdatei hinzu:

  <PropertyGroup> 
    <ServerGarbageCollection>false</ServerGarbageCollection>
  </PropertyGroup>

Wir haben diese Konfigurationsänderung an Ed-Pro vorgenommen, mit dotMemory haben wir Ed-Pros Speicher mit aktivierter Workstation Garbage Collection profiliert und dieselben Bildschirme wie im vorherigen Test geladen. Hier sind die Ergebnisse:

Die Speichernutzung ist erheblich verringert. Die Gen0-Zuweisungen sind praktisch nicht vorhanden. Über die Unterschiede im Diagramm hinaus erreichte die Server Garbage Collection-Speichernutzung 1 GB, während die Workstation Garbage Collection bei etwa 200 MB ihren Höchststand erreichte.

Jede Anwendung ist anders. Unsere Anwendung verwendete eine Menge temporärer Daten und nutzt daher eine Menge Gen0-Speicher. Ihre Anwendung könnte länger lebenden Speicher wie Gen1 oder Gen2 nutzen, bei dem Server Garbage Collection sehr viel Sinn macht. Mein Rat ist, Ihren Speicher unter verschiedenen Bedingungen zu profilieren, um eine Vorstellung davon zu bekommen, wie Speicher verwendet wird, und dann zu entscheiden, welcher Modus für Ihre Anwendung am besten ist.

Autor: Chuck Conway ist spezialisiert auf Software-Engineering und Generative KI. Verbinden Sie sich mit ihm in den sozialen Medien: X (@chuckconway) oder besuchen Sie ihn auf YouTube.

↑ Zurück nach oben

Das könnte dir auch gefallen