Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die automatische Speicherverwaltung ist einer der Dienste, die die Common Language Runtime während der verwalteten Ausführung bereitstellt. Der Garbage Collector der Common Language Runtime verwaltet die Zuordnung und Freigabe des Arbeitsspeichers für eine Anwendung. Für Entwickler bedeutet dies, dass Sie keinen Code schreiben müssen, um Speicherverwaltungsaufgaben auszuführen, wenn Sie verwaltete Anwendungen entwickeln. Die automatische Speicherverwaltung kann häufige Probleme beseitigen, z. B. das Vergessen, ein Objekt freizugeben und einen Speicherverlust zu verursachen, oder versuchen, auf den Speicher für ein Objekt zuzugreifen, das bereits freigegeben wurde. In diesem Abschnitt wird beschrieben, wie der Garbage Collector Speicher zuweist und freigibt.
Zuweisung des Arbeitsspeichers
Wenn Sie einen neuen Prozess initialisieren, reserviert die Laufzeit einen zusammenhängenden Adressraum für den Prozess. Dieser reservierte Adressraum wird als verwalteter Heap bezeichnet. Im verwalteten Heap steht ein Zeiger zur Verfügung, der auf die Adresse des nächsten im Heap zu speichernden Objekts zeigt. Anfangs ist dieser Zeiger auf die Basisadresse des verwalteten Heaps eingestellt. Alle Referenztypen werden im verwalteten Heap zugewiesen. Wurde von einer Anwendung der erste Referenztyp erstellt, wird für diesen Typ an der Basisadresse des verwalteten Heaps Speicherplatz belegt. Wenn die Anwendung das nächste Objekt erstellt, weist der Garbage Collector Speicher für das Objekt im Adressbereich direkt hinter dem ersten Objekt zu. Solange ein Adressbereich verfügbar ist, fährt der Garbage Collector auf diese Weise mit der Belegung von Arbeitsspeicher für neue Objekte fort.
Das Zuordnen von Speicher aus dem verwalteten Heap ist schneller als die nicht verwaltete Speicherzuweisung. Da die Laufzeit Speicher für ein Objekt durch Hinzufügen eines Werts zu einem Zeiger zuweist, ist sie fast so schnell wie das Zuweisen des Speichers aus dem Stapel. Da neue Objekte, die aufeinander zugeordnet werden, fortlaufend im verwalteten Heap gespeichert werden, kann eine Anwendung sehr schnell auf die Objekte zugreifen.
Freigeben des Arbeitsspeichers
Durch die Optimierungs-Engine des Garbage Collectors wird der beste Zeitpunkt für das Ausführen einer Garbage Collection bestimmt, die auf den erfolgten Speicherbelegungen basiert. Wenn der Garbage Collector eine Auflistung ausführt, gibt er den Speicher für Objekte frei, die von der Anwendung nicht mehr verwendet werden. Es bestimmt, welche Objekte nicht mehr verwendet werden, indem die Wurzeln der Anwendung untersucht werden. Jede Anwendung hat eine Reihe von Wurzeln. Jeder Stamm bezieht sich entweder auf ein Objekt im verwalteten Heap oder wird auf NULL festgelegt. Zu den Wurzeln einer Anwendung gehören statische Felder, lokale Variablen und Parameter im Stapel eines Threads sowie CPU-Register. Der Garbage Collector hat Zugriff auf eine Liste der aktiven Stammelemente, die vom JIT-Compiler (Just-In-Time) und der Common Language Runtime verwaltet wird. Mithilfe dieser Liste werden die Wurzeln einer Anwendung untersucht, und im Prozess wird ein Diagramm erstellt, das alle Objekte enthält, die aus den Wurzeln erreichbar sind.
Objekte, die sich nicht im Diagramm befinden, sind aus den Wurzeln der Anwendung nicht erreichbar. Diese nicht erreichbaren Objekte werden vom Garbage Collector als Abfall betrachtet, und der von diesen Objekten belegte Speicherplatz wird wieder freigegeben. Während einer Garbage Collection wird der verwaltete Heap nach den Blöcken des Adressraums durchsucht, in denen sich nicht erreichbare Objekte befinden. Da jedes nicht erreichbare Objekt erkannt wird, wird eine Speicherkopiefunktion verwendet, um die erreichbaren Objekte im Arbeitsspeicher zu komprimieren und die Adressblöcke freizugeben, die nicht erreichbaren Objekten zugeordnet sind. Sobald der Speicher für die erreichbaren Objekte komprimiert wurde, nimmt der Garbage Collector die erforderlichen Zeigerkorrekturen vor, sodass die Wurzeln der Anwendung auf die Objekte an ihren neuen Speicherorten verweisen. Außerdem wird der Zeiger des verwalteten Heaps auf die Position hinter dem letzten erreichbaren Objekt gesetzt. Beachten Sie, dass der Arbeitsspeicher nur komprimiert wird, wenn eine Auflistung eine erhebliche Anzahl nicht erreichbarer Objekte ermittelt. Wenn nach einer Garbage Collection alle Objekte in einem verwalteten Heap verbleiben, bedarf es auch keiner Speicherkomprimierung.
Um die Leistung zu verbessern, weist die Laufzeit Speicher für große Objekte in einem separaten Heap zu. Der Garbage Collector gibt automatisch den Speicher für große Objekte frei. Um das Verschieben großer Objekte im Arbeitsspeicher zu vermeiden, wird dieser Speicher jedoch nicht kompakt gemacht.
Generationen und Leistung
Zur Optimierung der Leistung des Garbage Collectors wird der verwaltete Heap in drei Generationen unterteilt: 0, 1 und 2. Der Garbage Collection-Algorithmus der Laufzeit basiert auf mehreren Verallgemeinerungen, die von der Computersoftwareindustrie durch Experimentieren mit Garbage Collection-Schemas als gültig erkannt wurden. Erstens kann die Garbage Collection schneller ausgeführt werden, wenn der Speicher nur in einem Teil des verwalteten Heaps komprimiert wird und nicht im gesamten Heap. Zweitens werden neuere Objekte kürzere Lebensdauern aufweisen, und ältere Objekte haben längere Lebensdauer. Schließlich neigen neuere Objekte dazu, miteinander in Beziehung zu stehen und von der Anwendung etwa zur gleichen Zeit genutzt zu werden.
Vom Garbage Collector der Laufzeit werden neue Objekte in Generation 0 gespeichert. Objekte, die früh in der Lebensdauer der Anwendung erstellt wurden und nach den Garbage Collections noch vorhanden sind, werden höher gestuft und werden in Generationen 1 und 2 gespeichert. Der Prozess der Objektförderung wird im weiteren Verlauf dieses Themas beschrieben. Da es weniger Zeit beansprucht, statt des gesamten verwalteten Heaps nur einen Teil davon zu komprimieren, ist es bei diesem Konzept auch möglich, bei einer Garbage Collection lediglich Speicher einer bestimmten Generationsstufe freizugeben und nicht den des gesamten verwalteten Heaps.
Tatsächlich wird eine Garbage Collection erst dann eingeleitet, wenn der Bereich von Generation 0 voll ist. Wenn eine Anwendung versucht, ein neues Objekt zu erstellen, und die Generation 0 bereits voll ist, stellt der Garbage Collector fest, dass kein Adressraum mehr in der Generation 0 verfügbar ist, um das Objekt zuzuweisen. Daraufhin wird eine Garbage Collection gestartet, um im Bereich der Generation 0 freien Adressraum zu schaffen. Dabei werden nur die Objekte im Bereich der Generation 0 untersucht und nicht alle Objekte im verwalteten Heap. Dies ist der effizienteste Ansatz, da neue Objekte tendenziell kurze Lebensdauer aufweisen, und es wird erwartet, dass viele der Objekte der Generation 0 nicht mehr von der Anwendung verwendet werden, wenn eine Auflistung ausgeführt wird. Darüber hinaus gibt eine Sammlung von Generation 0 allein oft genügend Arbeitsspeicher frei, damit die Anwendung weiterhin neue Objekte erstellen kann.
Nachdem der Garbage Collector einen Sammlungsvorgang der Generation 0 ausgeführt hat, komprimiert er den Speicher für die erreichbaren Objekte, wie weiter oben in diesem Thema unter Freigabe von Arbeitsspeicher erklärt. Der Garbage Collector stuft dann diese Objekte höher und betrachtet diesen Teil des verwalteten Heaps als Generation 1. Da Objekte, die Sammlungen überleben, tendenziell längere Lebensdauer haben, ist es sinnvoll, sie in eine höhere Generation zu fördern. Daher muss der Garbage Collector die Objekte in den Generationen 1 und 2 nicht jedes Mal erneut überprüfen, wenn er eine Sammlung der Generation 0 durchführt.
Nachdem der Garbage Collector die erste Garbage Collection der Generation 0 ausgeführt und die erreichbaren Objekte auf Generation 1 hochgestuft hat, betrachtet er den Rest des verwalteten Heaps als Generation 0. Es wird weiterhin Speicher für neue Objekte der Generation 0 zugewiesen, bis die Generation 0 voll ist und es erforderlich ist, eine andere Sammlung auszuführen. An diesem Punkt bestimmt das Optimierungsmodul des Garbage Collector, ob es erforderlich ist, die Objekte in älteren Generationen zu untersuchen. Wenn beispielsweise eine Sammlung der Generation 0 nicht genügend Arbeitsspeicher zurückgibt, damit die Anwendung erfolgreich versucht, ein neues Objekt zu erstellen, kann der Garbage Collector eine Sammlung der Generation 1 und dann der Generation 2 ausführen. Wenn dies nicht genügend Arbeitsspeicher zurückgibt, kann der Garbage Collector eine Sammlung der Generationen 2, 1 und 0 ausführen. Nach jeder Garbage Collection komprimiert der Garbage Collector die erreichbaren Objekte in Generation 0 und stuft sie auf Generation 1 herauf. Objekte der Generation 1, die Sammlungen überleben, werden zur Generation 2 heraufgestuft. Da der Garbage Collector nur drei Generationen unterstützt, verbleiben Objekte in Generation 2, die eine Sammlung überleben, in Generation 2, bis sie in einer zukünftigen Sammlung als nicht erreichbar angesehen werden.
Freigeben des Arbeitsspeichers für nicht verwaltete Ressourcen
Für den Großteil der von Der Anwendung erstellten Objekte können Sie sich auf den Garbage Collector verlassen, um automatisch die erforderlichen Speicherverwaltungsaufgaben auszuführen. Nicht verwaltete Ressourcen erfordern jedoch eine explizite Bereinigung. Die am häufigsten verwendete Art von nicht verwalteter Ressource ist ein Objekt, das eine Betriebssystemressource umschließt, z. B. ein Dateihandle, ein Fensterhandle oder eine Netzwerkverbindung. Obwohl der Garbage Collector die Lebensdauer eines verwalteten Objekts nachverfolgen kann, das eine nicht verwaltete Ressource kapselt, verfügt er nicht über spezifische Kenntnisse zum Bereinigen der Ressource. Wenn Sie ein Objekt erstellen, das eine nicht verwaltete Ressource kapselt, wird empfohlen, den erforderlichen Code zum Bereinigen der nicht verwalteten Ressource in einer öffentlichen Dispose-Methode bereitzustellen. Durch die Bereitstellung einer Dispose-Methode können Benutzer des Objekts den Arbeitsspeicher explizit freigeben, wenn sie mit dem Objekt fertig sind. Wenn Sie ein Objekt verwenden, das eine nicht verwaltete Ressource kapselt, sollten Sie "Dispose " beachten und es bei Bedarf aufrufen. Weitere Informationen zum Bereinigen nicht verwalteter Ressourcen und ein Beispiel für ein Entwurfsmuster für die Implementierung von Dispose finden Sie unter Garbage Collection.