Ich werde gleich sagen: Ich warte nie auf eine ausführliche Antwort auf diese Frage zur sozialen Sicherheit. Das ist dumm und in meinem Fall egoistisch. Meiner Meinung nach ist es jedoch neben dem allgemeinen Interesse an der Plattform sehr nützlich zu wissen, wie es funktioniert, weil Dies beseitigt eine Reihe von Problemen. Beispielsweise wird die Option ausgeschlossen, wenn der Entwickler der Ansicht ist, dass Dispose
automatisch aufgerufen wird und Sie sie nicht selbst aufrufen müssen. Oder wenn der Entwickler erfahrener ist, hilft er ihm automatisch, auf der Ebene des Muskelgedächtnisses Code zu schreiben, der zu der geringsten Anzahl von Problemen führt.
Eine andere Frage, die ich subjektiv nicht wirklich mag, ist, wie seine Arbeit erklärt wird. Daher schlage ich einen alternativen Ansatz vor, der in meinem Buch .NET Platform Architecture beschrieben ist .
Wenn wir genau verstehen wollen, warum diese beiden Speicherverwaltungsalgorithmen ausgewählt wurden: Sweep und Compact, müssen wir Dutzende von Speicherverwaltungsalgorithmen berücksichtigen, die es auf der Welt gibt: beginnend mit gewöhnlichen Wörterbüchern und endend mit sehr komplexen sperrenfreien Strukturen. Stattdessen begründen wir einfach die Wahl und verstehen dadurch , warum die Wahl so getroffen wurde. Wir sehen uns das Booster-Startheft nicht mehr an: Wir haben eine vollständige Dokumentation in der Hand.
Der Streit ist für beide Seiten von Vorteil: Wenn er nicht klar ist, werde ich die unklaren Punkte im Buch korrigieren, von denen ein kleiner Teil der gegebene Text ist.

Ich habe das Format der Argumentation so gewählt, dass Sie das Gefühl haben, dass die Architekten der Plattform und ich zu den gleichen Ergebnissen gekommen sind, zu denen die echten Architekten in der Microsoft-Zentrale in Redmond gekommen sind.
Basierend auf der Klassifizierung der zugewiesenen Objekte anhand ihrer Größe können Sie den Speicherplatz für die Speicherzuweisung in zwei große Abschnitte unterteilen: einen Ort mit Objekten, deren Größe unter einem bestimmten Schwellenwert liegt, und einen Ort mit einer Größe über diesem Schwellenwert, um festzustellen, welche Unterschiede bei der Verwaltung dieser Gruppen (basierend auf) auftreten können ihre Größe) und was daraus wird.
Wenn wir die Verwaltung herkömmlicher " kleiner " Objekte in Betracht ziehen, können wir feststellen, dass es für uns sehr teuer ist, Speicherverwaltungsdatenstrukturen zu verwalten, in denen Links zu jedem dieser Objekte gespeichert werden, wenn wir uns an die Idee halten, Informationen zu jedem Objekt zu speichern. Am Ende kann sich herausstellen, dass Sie zum Speichern von Informationen zu einem Objekt so viel Speicher benötigen, wie das Objekt selbst benötigt. Stattdessen sollten Sie berücksichtigen: Wenn wir während der Speicherbereinigung von den Wurzeln aus tanzen und tief in den Graphen durch die ausgehenden Felder des Objekts gehen und nur eine lineare Passage entlang des Heaps benötigen, um Müllobjekte zu identifizieren, müssen wir dann Informationen zu jedem Objekt in den Speicherverwaltungsalgorithmen speichern? Die Antwort liegt auf der Hand: Es besteht keine Notwendigkeit dafür. Wir können also versuchen, von der Tatsache auszugehen, dass wir solche Informationen nicht speichern sollten: Wir können eine Reihe linear durchlaufen, die Größe jedes Objekts kennen und den Zeiger jedes Mal um die Größe des nächsten Objekts bewegen.
Es gibt keine zusätzlichen Datenstrukturen auf dem Heap, die Zeiger auf jedes Objekt enthalten, das der Heap steuert.
Wenn wir jedoch keinen Speicher mehr benötigen, müssen wir ihn freigeben. Und wenn wir Speicher freigeben, fällt es uns schwer, uns auf den linearen Durchgang des Haufens zu verlassen: Er ist lang und nicht effektiv. Infolgedessen kommen wir zu dem Schluss, dass wir Informationen über freie Speicherbereiche irgendwie speichern müssen.
Der Heap enthält Listen mit freiem Speicher.
Wenn, wie wir beschlossen haben, Informationen über freie Bereiche gespeichert werden sollen und während Speicherplatz freigegeben wurde, diese Bereiche zu klein waren, stoßen wir zunächst auf das gleiche Problem beim Speichern von Informationen über freie Bereiche, auf das wir bei der Betrachtung besetzter Bereiche gestoßen sind (wenn Auf den Seiten des belegten Objekts wurde ein Objekt freigegeben, um Informationen darüber zu speichern, ist es im schlimmsten Fall 2/3 seiner Größe erforderlich. Zeiger + Größe versus SyncBlockIndex + VMT + ein Feld - im Fall des Objekts). Das klingt wieder verschwenderisch, müssen Sie zugeben: Es ist nicht immer ein Glück, eine Gruppe von Objekten zu befreien, die aufeinander folgen. Normalerweise werden sie auf chaotische Weise freigesetzt. Im Gegensatz zu ausgelasteten Sites, die wir nicht linear durchsuchen müssen, müssen wir nach freien Sites suchen, da wir diese möglicherweise erneut benötigen, wenn wir Speicher zuweisen. Daher entsteht ein völlig natürlicher Wunsch, die Fragmentierung zu verringern und den Haufen zusammenzudrücken, indem alle besetzten Bereiche an freie Orte verschoben werden, wodurch ein großer Bereich des freien Bereichs gebildet wird, in dem Speicher zugewiesen werden kann.
Hier kommt die Idee des Verdichtungsalgorithmus her.
Aber warte, sagst du? Immerhin kann dieser Vorgang sehr schwierig sein. Stellen Sie sich vor, Sie haben ein Objekt ganz am Anfang des Heaps freigegeben. Und was, sagst du, brauchst du, um alles zu bewegen? Natürlich können Sie sich das Thema Vektoranweisungen der CPU ausdenken, mit denen Sie einen riesigen belegten Speicherbereich kopieren können. Dies ist jedoch nur der Beginn der Arbeit. Wir müssen auch alle Zeiger aus den Feldern von Objekten auf Objekte fixieren, die Bewegungen erfahren haben. Dieser Vorgang kann sehr lange dauern. Nein, wir müssen von etwas anderem ausgehen. Zum Beispiel, indem Sie das gesamte Segment des Heapspeichers in Sektoren aufteilen und separat damit arbeiten. Wenn wir in jedem Sektor separat arbeiten (für die Vorhersagbarkeit und Skalierung dieser Vorhersagbarkeit - vorzugsweise für feste Größen), scheint die Idee der Komprimierung nicht so schwer zu sein: Es reicht aus, einen einzelnen Sektor zu komprimieren, und dann können Sie sogar anfangen, über die Zeit zu sprechen, die zum Komprimieren eines solchen Sektors erforderlich ist .
Nun bleibt zu verstehen, auf welcher Grundlage in Sektoren unterteilt werden soll. Hier müssen wir uns der zweiten Klassifizierung zuwenden, die auf der Plattform eingeführt wird: Speicherfreigabe, basierend auf der Lebensdauer der einzelnen Elemente.
Die Unterteilung ist einfach: Wenn wir berücksichtigen, dass wir mit zunehmenden Adressen Speicher zuweisen, werden die ersten ausgewählten Objekte zu den ältesten und die Objekte in den älteren Adressen zu den jüngsten. Wenn Sie klug sind, können Sie außerdem zu dem Schluss kommen, dass Objekte in Anwendungen in zwei Gruppen unterteilt sind: diejenigen, die für ein langes Leben erstellt wurden, und diejenigen, die für ein sehr geringes Leben erstellt wurden. Zum Beispiel, um Zeiger auf andere Objekte in Form einer Sammlung vorübergehend zu speichern. Oder die gleichen DTO-Objekte. Dementsprechend erhalten wir von Zeit zu Zeit, wenn wir einen Haufen zusammendrücken, eine Reihe von langlebigen Objekten - in den unteren Adressen und eine Reihe von kurzlebigen - im Senior.
So haben wir Generationen erhalten .
Wenn wir die Erinnerung in Generationen aufteilen, haben wir die Möglichkeit, seltener auf die Objekte der älteren Generation zu schauen, die immer mehr werden.
Aber es stellt sich eine andere Frage: Wenn wir nur zwei Generationen haben, werden wir Probleme bekommen. Oder wir werden versuchen, GC maskenlos schnell zum Laufen zu bringen: Dann werden wir bei der Größe der jüngeren Generation versuchen, die Mindestgröße zu erreichen. Infolgedessen versagen Objekte in der älteren Generation versehentlich (wenn der GC "gerade jetzt, während einer wütenden Speicherzuweisung für viele Objekte" funktioniert hat). Um ein versehentliches Versagen zu minimieren, werden wir die Größe der jüngeren Generation erhöhen. Dann arbeitet der GC der jüngeren Generation lange genug, verlangsamt und verlangsamt die Anwendung.
Der Ausweg ist die Einführung der "mittleren" Generation. Teenager. Mit anderen Worten, wenn Sie bis zur Pubertät leben, ist es wahrscheinlicher, dass Sie bis ins hohe Alter leben. Die Essenz seiner Einführung besteht darin, ein Gleichgewicht zwischen der kleinsten jüngeren Generation und der stabilsten älteren Generation zu erreichen , bei der es besser ist, nichts zu berühren. Dies ist eine Zone, in der das Schicksal der Objekte noch nicht entschieden ist. Die erste Generation (vergessen Sie nicht, was wir von Grund auf neu denken) ist ebenfalls klein und GC sieht dort seltener aus. GC ermöglicht es somit den Objekten, die sich in der temporären ersten Generation befinden, nicht in die ältere Generation zu gelangen, was äußerst schwierig zu sammeln ist.
So kamen wir auf die Idee von drei Generationen.
Die nächste Optimierungsebene ist der Versuch, die Komprimierung abzulehnen. Wenn Sie es nicht tun, werden wir schließlich eine riesige Schicht Arbeit los. Kommen wir zurück zum Thema kostenlose Websites.
Wenn wir den gesamten im Heap verfügbaren Speicher aufgebraucht haben und GC aufgerufen wurde, besteht ein natürlicher Wunsch, die Komprimierung zugunsten einer weiteren Zuweisung von Speicher innerhalb der freigegebenen Abschnitte zu verweigern, wenn ihre Größe ausreicht, um eine bestimmte Anzahl von Objekten aufzunehmen. Hier kommen wir zu der Idee eines zweiten Algorithmus zum Freigeben von Speicher im GC namens Sweep
: Wir komprimieren den Speicher nicht, wir verwenden Hohlräume von freigegebenen Objekten, um neue Objekte zu platzieren
Deshalb haben wir alle Grundlagen von GC-Algorithmen beschrieben und begründet.
Nach zwei Tagen können wir also einige Schlussfolgerungen ziehen. So wie ich es verstehe, verstehen die meisten Leute den größten Teil des Textes oder sogar den ganzen. Einige Leute antworteten, dass sie nicht verstanden, andere teilweise verstanden. Der Streit wurde von einem Team von Lesern gewonnen, wenn auch mit einem geringen Vorsprung, wie sie sagen. Aber wie gesagt, jeder wird davon profitieren: Der Text wird geändert und ergänzt. Außerdem an beiden Stellen aktualisiert: sowohl im Buch als auch hier im Artikel.
