Einige (zumindest Monos und .NETs) Garbage Collectors haben einen Kurzzeitspeicherbereich, den sie häufig durchsuchen, und einen sekundären Speicherbereich, den sie seltener durchsuchen. Mono nennt das einen Kindergarten.
Um herauszufinden, welche Objekte entsorgt werden können, scannen sie alle Objekte, beginnend mit Wurzeln, dem Stapel und den Registern, und entsorgen alle Objekte, auf die nicht mehr verwiesen wird.
Meine Frage ist, wie sie verhindern, dass alle verwendeten Speicher bei jeder Erfassung gescannt werden? Grundsätzlich können Sie nur dann herausfinden, welche Objekte nicht mehr verwendet werden, wenn Sie alle Objekte und ihre Referenzen scannen. Dies würde jedoch verhindern, dass das Betriebssystem den Speicher auslagert, obwohl es nicht von der Anwendung verwendet wird, und es scheint, dass eine große Menge an Arbeit erledigt werden muss, auch für "Nursery Collection". Es fühlt sich nicht so an, als würden sie durch die Nutzung eines Kindergartens viel gewinnen.
Vermisse ich etwas oder scannt der Müllsammler tatsächlich jedes Objekt und jede Referenz, wenn er eine Sammlung durchführt?
quelle
Antworten:
Die grundlegenden Beobachtungen, mit denen die Sammlung von Speicherbereinigungen für Generationen vermieden werden kann, dass alle Objekte älterer Generationen gescannt werden müssen, sind:
In vielen GC-Frameworks ist es dem Garbage Collector möglich, Objekte oder Teile davon so zu kennzeichnen, dass der erste Versuch, darauf zu schreiben, einen speziellen Code auslöst, der die Tatsache aufzeichnet, dass sie geändert wurden. Ein Objekt oder ein Teil davon, das unabhängig von seiner Erzeugung geändert wurde, muss in der nächsten Sammlung gescannt werden, da es Verweise auf neuere Objekte enthalten kann. Andererseits ist es sehr häufig, dass es viele ältere Objekte gibt, die zwischen den Sammlungen nicht geändert werden. Die Tatsache, dass Scans niedrigerer Generationen solche Objekte ignorieren können, kann dazu führen, dass solche Scans viel schneller ausgeführt werden, als dies sonst der Fall wäre.
Man beachte übrigens, dass selbst wenn man nicht erkennen kann, wann Objekte geändert wurden und bei jedem GC-Durchgang alles gescannt werden müsste, die generationsbedingte Speicherbereinigung die Leistung eines Kompaktierungskollektors im Sweep-Stadium verbessern könnte. In einigen eingebetteten Umgebungen (insbesondere in solchen, in denen die Geschwindigkeit zwischen sequentiellen und zufälligen Speicherzugriffen kaum oder gar nicht unterschiedlich ist) ist das Verschieben von Speicherblöcken im Vergleich zum Markieren von Referenzen relativ teuer. Selbst wenn die "Mark" -Phase mit einem Generationskollektor nicht beschleunigt werden kann, kann es sich daher lohnen, die "Sweep" -Phase zu beschleunigen.
quelle
Die GCs, auf die Sie sich beziehen, sind generationsübergreifende Garbage Collectors. Sie wurden entwickelt, um das Beste aus einer als "Kindersterblichkeit" oder "Generationshypothese" bekannten Beobachtung herauszuholen, was bedeutet, dass die meisten Objekte sehr schnell unerreichbar werden. Sie scannen zwar von den Wurzeln aus, ignorieren aber alle alten Objekte . Daher müssen sie nicht die meisten Objekte im Speicher scannen, sondern nur junge Objekte (auf Kosten der Nichterkennung nicht erreichbarer alter Objekte, zumindest nicht zu diesem Zeitpunkt).
"Aber das ist falsch", höre ich Sie schreien, "alte Objekte können und verweisen auf junge Objekte". Sie haben Recht, und es gibt verschiedene Lösungen, bei denen es darum geht, schnell und effizient Wissen zu erlangen, alte Objekte zu überprüfen und zu ignorieren. Sie beschränken sich auf die Aufzeichnung von Objekten oder auf kleine (größer als Objekte, aber viel kleiner als der gesamte Haufen) Speicherbereiche, die Zeiger auf jüngere Generationen enthalten. Andere haben diese weitaus besser beschrieben als ich, deshalb gebe ich Ihnen nur ein paar Stichwörter: Kartenkennzeichnung, gespeicherte Sätze, Schreiben von Barrieren. Es gibt auch andere Techniken (einschließlich Hybriden), aber diese umfassen die gängigen Ansätze, die mir bekannt sind.
quelle
Um herauszufinden, welche Kindergartenobjekte noch vorhanden sind, muss der Collector nur den Stammsatz und alle alten Objekte scannen, die seit der letzten Sammlung mutiert wurden , da ein altes Objekt, das kürzlich nicht mutiert wurde, möglicherweise nicht auf ein junges Objekt verweisen kann . Es gibt verschiedene Algorithmen, um diese Informationen auf unterschiedlichen Genauigkeitsniveaus zu halten (von einem exakten Satz mutierter Felder bis zu einem Satz von Seiten, auf denen möglicherweise Mutationen aufgetreten sind), aber alle beinhalten im Allgemeinen eine Art Schreibsperre : Code, der auf jeder Referenz ausgeführt wird Feldmutation, die die Buchhaltung des GC aktualisiert.
quelle
Die älteste und einfachste Generation von Garbage Collectors hat tatsächlich den gesamten Speicher gescannt und musste währenddessen alle anderen Verarbeitungsvorgänge stoppen. Spätere Algorithmen haben dies auf verschiedene Weise verbessert - indem sie das Kopieren / Scannen inkrementell oder parallel ausführen. Die meisten modernen Garbage Collectors unterteilen Objekte in Generationen und verwalten generationsübergreifende Zeiger sorgfältig, sodass neuere Generationen erfasst werden können, ohne ältere zu stören.
Der entscheidende Punkt ist, dass Garbage Collectors eng mit dem Compiler und dem Rest der Laufzeit zusammenarbeiten, um die Illusion aufrechtzuerhalten, dass der gesamte Speicher überwacht wird.
quelle
Grundsätzlich ... GC verwendet "Eimer", um zu trennen, was verwendet wird und was nicht. Sobald es überprüft wurde, löscht es nicht verwendete Objekte und verschiebt alles andere in die 2. Generation (die weniger häufig überprüft wird als die 1. Generation) und verschiebt dann Objekte, die in der 2. Den noch verwendet werden, in die 3. Generation.
Daher sind Dinge in der 3. Generation normalerweise Objekte, die aus irgendeinem Grund offen bleiben, und GC prüft sie dort nicht sehr oft.
quelle
Der von diesem GC üblicherweise verwendete Algorithmus ist das Naive Mark-and-Sweep
Sie sollten sich auch der Tatsache bewusst sein, dass dies nicht von C # selbst verwaltet wird, sondern von der sogenannten CLR .
quelle