AngelikaLanger.com - Der Garbage-First Garbage Collector (G1) - Übersicht über die Funktionalität (original) (raw)
Der Garbage-First Garbage Collector (G1) - Übersicht über die Funktionalität
Memory Management Der Garbage-First Garbage Collector (G1) - Übersicht über die Funktionalität Java Magazin, Februar 2011 Klaus Kreft & Angelika Langer | Dies ist das Manuskript eines Artikels, der im Rahmen einer Kolumne mit dem Titel "Effective Java" im Java Magazin erschienen ist. Die übrigen Artikel dieser Serie sind ebenfalls verfügbar (click here). |
---|
In den letzten Beiträgen (siehe /GC5/ und /GC6/)haben wir uns die Architektur und das Tuning der bisherigen Generational Garbage Collection der Sun JVM angesehen. Seit einigen Jahren arbeitet Sun schon an einem ganz neuen Garbage Collector mit einer neuen, eigenständigen Architektur. Garbage-First Garbage Collector (oder kurz: G1) heißt er. Wir wollen uns ihn in diesem Artikel genauer ansehen.
Motivation
Mit dem CMS (siehe /GC4/) gibt es auf der Old Generation einen Garbage Collector, dessen Charakteristikum möglichst kurze Pausen (d.h. möglichst kurze Unterbrechungen der Anwendung durch den Garbage Collector) sind. Leider ist die Benutzung des CMS unter Umständen ziemlich ‚tricky’. Kann er seine Arbeit nicht schnell genug erledigen oder kommt es zu so starker Heap-Fragmentierung, dass neue Objekte nicht mehr in der Old Generation angelegt werden können, wird eine Full Collection ausgelöst, die die Anwendung ziemlich lange unterbricht. Hier kann man dann zwar mit explizitem Tuning versuchen, die Full Collections zu vermeiden (siehe /GC4/); es wird aber nicht immer gelingen. Ein weiteres Problem ist, dass bei Veränderung des Speicherverhaltens (zum Beispiel nach Einbau neuer Features) ein Tuning wieder nötig wird.
An dieser Stelle soll der G1 nun Abhilfe schaffen. Er soll konstant kurze Pausen, bei gutem bis akzeptablem Durchsatz, liefern.
Dazu kommt, dass er einfach an die spezifischen Anforderungen angepasst werden kann. Man kann von außen mitgeben,
- wie viel Zeit die CPU der Anwendung zur Verfügung stehen soll und
- wie viel Zeit der Garbage Collector die CPU benutzen darf.
Dies geht im Detail so, dass man eine Untergrenze für den Abstand zwischen dem Start zweier aufeinander folgender Garbage Collection Pausen und eine Obergrenze für die Pause selbst vorgibt. Dies geht mit Hilfe von JVM Optionen. Die Option für die Untergrenze des Abstands zwischen den Pausenstarts ist –XX:GCPauseIntervalMillis(Defaultwert: 500ms) und die Option für die Obergrenze der Pause ist–XX:MaxGCPauseMillis (Defaultwert: 200ms). Klarerweise mussGCPauseIntervalMillisgrößer als MaxGCPauseMillis sein, damit zwischen dem Start der Garbage Collections Pausen auch noch Zeit für die Anwendung bleibt und nicht nur für die Garbage Collection Pause. Wenn man die Ungleichheitsrelation bei den Vorgaben nicht einhält, bricht die JVM den Start ab mit einer Fehlermeldung, die auf diesen Umstand hinweist.
Abbildung 1: G1 Laufzeit-Vorgaben
Abbildung 1 zeigt beispielhaft die Verteilung der CPU auf Applikation und Garbage Collector zusammen mit den definierenden Vorgaben. Wie der Garbage Collector dafür sorgt die Vorgaben einzuhalten, werden wir uns im nächsten Artikel im Detail ansehen. Fangen wir hier erst mal mit einer Übersicht zum Aufbau und zur Funktionalität des G1 an.
Funktionale Übersicht
Die Motivation für die Entwicklung des G1 geht zwar über den Vergleich mit dem CMS. Trotzdem ist der G1 anders als der CMS nicht nur ein Old Generation Garbage Collector. Er ist vielmehr ein völlig neuer Garbage Collector für den gesamten User-Heap mit einer neuen eigenständigen Architektur. Der Perm-Bereich (siehe /GC1/) arbeitet aber wie bisher. Deshalb gehen wir auf ihn in diesem Artikel nicht weiter ein.
Aufteilung in Region
Der gesamte User-Heap wird beim G1 in lauter gleichgroße Regionen (regions) aufgeteilt. In den ersten Versionen des G1 waren die Regionen ein MByte groß. Seit dem Release 1.6.0_18 können die Regionsgröße nun 1 bis 32 MByte sein (zusätzlich muss es auch eine Potenz von 2 sein). Der G1 wählt die Größe nach der einfachen Regel: kleiner Heap - kleine Regionsgröße, großer Heap - große Regionsgröße. Sollte der G1 den Heap während des Programmablaufs vergrößern, wird die Regionsgröße aber nicht mehr verändert. Die Regionsgröße lässt sich auch von außen festlegen. Mit der JVM-Option -XX:G1HeapRegionSize=8M wird sie zum Beispiel auf acht MByte gesetzt.
Der G1 verwendet eine spezifische Art von Generational Garbage Collection. Entsprechend enthält eine Region nur junge Objekte (Young Region) oder nur alte Objekte (Old Region). Natürlich kann eine Region auch aktuell gar nicht genutzt werden und leer sein. Die Young Regions teilen sich ihrerseits noch mal in zwei Typen von Regionen auf. Da sind zum einen die Regionen, in denen aktuell Objekte angelegt werden, und zum anderen die Survivor Regions. Die Survivor Regions haben eine ähnliche Aufgabe wie die Survivor Spaces (siehe /GC1/) bei der bisherigen Garbage Collection: Sie nehmen Objekte auf, die bei der Garbage Collection (beim G1 spricht man meist von Evacuation) aus einer Young Region herauskopiert wurden, aber noch nicht direkt in eine Old Region kopiert werden sollten.
Abbildung 2: G1 User-Heap
Abbildung 2 zeigt einen beispielhaften G1 User-Heap. Man sieht die Aufteilung in gleichgroße Regionen. Auffallend im Vergleich zur bisherigen Garbage Garbage Collection ist, dass die logisch zusammengehörenden Regionen (hier: die drei Regionen der Old Generation) keinen zusammenhängenden Speicher belegen müssen.
Die Zuordnung von Region zu enthaltenem Typ von Objekten ist im G1 immer nur temporär. So kann eine Old Region nach ihrer Evakuierung für die Allokation neuer Objekte, als Survivor Region, als Old Region oder auch erst mal gar nicht genutzt werden. Das hängt allein davon ab, welcher Typ von Region benötigt wird.
Objekt Allokation
Wie bereits beschrieben gibt es eine oder mehrere Regionen, die speziell dazu benutzt werden, dass in ihnen neuen Objekte angelegt werden. Wie auch schon bei den bisherigen Garbage Collectoren (siehe /GC2/) erfolgt die Allokation mit Hilfe von TLABs (Thread Allocation Buffer). Das heißt, jedem Anwendungsthread wird ein spezifischer Bereich in der Region (der TLAB) zugeordnet, in dem er ohne weitere Synchronisation neue Objekte anlegen kann. Die Zuordnung des TLABs zu dem Anwendungsthreads erfolgt mit einer Compare-And-Swap-Operation (CAS). CAS-Operationen sind atomar und können deshalb ohne Synchronisation ausgeführt werden (siehe /CAS/). Daraus ergibt sich ein sehr geringer Synchronisationsoverheads zwischen den Anwendungsthreads, so dass sichergestellt ist, dass die Objekt Allokation auch auf einer Multicore-/Multiprozessor-Plattform gut skaliert.
Für größere Objekte gibt es spezielle Allokationsstrategien. Je nach Größe werden sie in eigenen TLABs oder sogar in eigenen Regionen angelegt.
Objekt Evakuierung
Die überlebenden Objekte einer Young Region werden bei der Garbage Collection je nach Alter und Anzahl entweder in eine Survivor Region oder eine Old Region kopiert. Der Speicher der Young Region wird danach zur Wiederverwendung freigegeben. Es wird also ähnlich wie bei der Young Generation der bisherigen Garbage Collection ein Scavenger Ansatz verwendet (siehe /GC2/).
Die Evakuierung der lebenden Objekte erfolgt in einer Garbage Collection Pause; das heißt, die Anwendungsthreads stehen so lange. Die Evakuierung ist die letzte Tätigkeit in der Pause. Vorher werden verschiedene Verwaltungsarbeiten durchgeführt, die dazu dienen, die überlebenden Objekte zu bestimmen. Was dabei genau geschieht, schauen wir uns im Detail im nächsten Artikel an.
Wichtig ist, dass alle Tätigkeiten der Garbage Collection Pause in relativ kleine Teile (Sub Tasks) zerlegt werden, die parallel zueinander durch verschiedene Garbage Collector Threads bearbeitet werden können. So wird erreicht, dass die Garbage Collection gut auf einer Multicore-/Multiprozessor-Plattform skaliert und die Garbage Collection Pause möglichst klein ist. Defaultmäßig werden soviel Garbage Collector Threads genutzt, wie es Prozessorcores auf der Plattform gibt.
Old Regions werden bei der Garbage Collection nur dann berücksichtigt, wenn sie nur noch relativ wenig lebende Objekte enthalten; oder anders formuliert: wenn sie viel Müll (Garbage) enthalten. Daher kommt auch der Name Garbage-First (kurz: G1) Garbage Collector.
Old Regions kann man bezüglich der Garbage Collection in drei Kategorien aufteilen:
- Regionen, in denen es gar keine lebenden Objekte gibt. Sie werden direkt zur Wiederverwendung freigegeben.
- Regionen, in denen es relativ wenige lebende Objekte gibt. Die Objekte werden evakuiert und die Regionen werden freigegeben. Wir werden im nächsten Artikel sehen, dass für die Auswahl weitere Kriterien (neben der Anzahl lebender Objekte) eine Rolle spielen.
- Regionen, in denen es relativ viele lebende Objekte gibt. Sie werden bei der Garbage Collection gar nicht berücksichtigt. Es wird vielmehr gewartet, bis in diesen Regionen weitere Objekte gestorben sind, und diese Regionen dann in eine der beiden vorhergehenden Kategorien fallen. Erst dann sind sie für den Garbage Collector wieder interessant.
Da beim G1 die Regionen, die bei der Garbage Collection berücksichtigt werden, dynamisch ausgewählt werden, hat sich ein Begriff für diese Regionen gebildet: Collection Set.
Ob überhaupt Old Regions bei der Garbage Collection berücksichtigt werden, hängt von dem Modus ab, in dem der G1 gerade läuft. Es gibt zwei Modi: Fully Young Mode und Partially Young Mode. Im Fully Young Mode gehören alle Young Regions zum Collections Set. Beim Partially Young Mode besteht der Collection Set auch wieder aus allen Young Regions; zusätzlich kommen die Old Regions dazu, die keine oder relativ wenig lebende Objekte enthalten. Der G1 schaltet während des Ablaufs dynamisch zwischen den Modi hin und her. Welche Kriterien er dafür verwendet, schauen wir uns im nächsten Artikel genauer an.
Abbildung 3: G1 Garbage Collection
Abbildung 3 zeigt ein Beispiel für eine G1 Garbage Collection im Partially Young Mode, d.h. Young und Old Regions werden berücksichtigt. Die linke Seite zeigt den Heap vor der Collection, die rechte Seite danach. Die kleinen weißen Punkte in den Regionen symbolisieren die lebenden Objekte.
Die Old Region oben links enthält noch zu viele lebende Objekte. Sie gehört deshalb nicht zum Collection Set und wird daher nicht in die Garbage Collection mit einbezogen. Die Old Region ganz rechts enthält gar keine lebenden Objekte und wird direkt freigegeben. Die lebenden Objekte aus den anderen drei Regionen - es sind zwei Young Regions (bestehend aus je einer Allocation Region und einer Survivor Region) und eine Old Region - werden in eine neue Old Region kopiert. Danach werden diese Regionen freigegeben.
G1 und JDK Versionen
Als der G1 mit JDK 6 Update 14 zum ersten Mal in einer offiziellen Java Version verfügbar war, gab es Missverständnisse bezüglich der Release Notes. Die Orignalformulierung konnte so verstanden werden, dass man den G1 nicht nutzen dürfe, wenn man keinen Supportvertrag mit Sun hatte. Die überarbeitete Formulierung machte dann klar, dass ohne Supportvertrag die Benutzung auf eigene Gefahr möglich ist. Entsprechen muss man, wenn man G1 mit JDK 6 nutzen will, nicht nur die JVM Option –XX:+UseG1GC setzen, die den G1 als Garbage Collector auswählt, sondern zusätzlich auch –XX:+UnlockExperimentalVMOptions.
Der fertige und vollständig unterstütze G1 war für den JDK 7 offiziell angekündigt. Entsprechend brauchte man bei neueren Vorabversionen des JDK 7 aus dem OpenJDK die Option –XX:+UnlockExperimentalVMOptionsnicht mehr. Bis zu welcher Produktionsversionsnummer die Experimental-Option genau benötigt wird, hängt von der Betriebssystem-Plattform (Windows oder Linux) ab.
Als klar wurde, dass der Releasetermin für den JDK 7 mit September 2010 nicht eingehalten werden konnte, wurden die schon fast fertigen Teile der bisherigen Entwicklung als neuer JDK 7 auf Mitte 2011 und die anderen Teile als JDK 8 auf Ende 2012 verschoben. Für den G1 hatte man eine besonders salomonische Entscheidung parat: er ist offiziell Teil des JDK 6.
Danksagung
Abgesehen von einem JavaOne Vortrag aus dem Jahre 2008 (siehe /JONE/) und einem White Paper für das International Symposium on Memory Management 2004 (siehe /ISMM/) gibt es bis heute kaum substantielle Veröffentlichungen zu G1. Dieser Artikel basiert daher neben den oben erwähnten Quellen zum größten Teil auf Informationen, die wir direkt von Tony Printezis (dem Chefentwickler von G1) erhalten haben. Dafür möchten wir uns an dieser Stelle noch einmal recht herzlich bei ihm bedanken.
Zusammenfassung
Um verlässliche kurze Pausen bei der Garbage Collection zu haben, wurde von Sun/Oracle der G1 Garbage Collector entwickelt. Dieser Artikel war eine Übersicht über die Funktionalität des G1. Im nächsten Artikel schauen wir uns dann die Details an.
Literaturverweise
Die gesamte Serie über Garbage Collection:
/GC1/ | Generational Garbage Collection Klaus Kreft & Angelika Langer, Java Magazin, February 2010 URL: http://www.angelikalanger.com/Articles/EffectiveJava/49.GC.GenerationalGC/49.GC.GenerationalGC.html |
---|---|
/GC2/ | Young Generation Garbage Collection Klaus Kreft & Angelika Langer, Java Magazin, April 2010 URL: http://www.angelikalanger.com/Articles/EffectiveJava/50.GCYoungGenGC/50.GC.YoungGenGC.html |
/GC3/ | Old Generation Garbage Collection – Mark-and-Compact Klaus Kreft & Angelika Langer, Java Magazin, June 2010 URL: http://www.angelikalanger.com/Articles/EffectiveJava/51.GC.OldGen.MarkCompact/51.GC.OldGen.MarkCompact.html |
/GC4/ | Old Generation Garbage Collection – Concurrent-Mark-Sweep (CMS) Klaus Kreft & Angelika Langer, Java Magazin, August 2010 URL: http://www.angelikalanger.com/Articles/EffectiveJava/52.GC.OldGen.CMS/52.GC.OldGen.CMS.html |
/GC5/ | Garbage Collection Tuning – Die Ziele Klaus Kreft & Angelika Langer, Java Magazin, Oktober 2010 URL: http://www.angelikalanger.com/Articles/EffectiveJava/53.GC.Tuning.Goals/53.GC.Tuning.Goals.html |
/GC6/ | Garbage Collection Tuning – Die Details Klaus Kreft & Angelika Langer, Java Magazin, Dezember 2010 URL: http://www.angelikalanger.com/Articles/EffectiveJava/54.GC.Tuning.Details/54.GC.Tuning.Details.html |
/GC7/ | Der Garbage-First Garbage Collector (G1) - Übersicht über die Funktionalität Klaus Kreft & Angelika Langer, Java Magazin, Februar 2011 URL: http://www.angelikalanger.com/Articles/EffectiveJava/55.GC.G1.Overview/55.GC.G1.Overview.html |
/GC8/ | Der Garbage-First Garbage Collector (G1) - Details und Tuning Klaus Kreft & Angelika Langer, Java Magazin, April 2011 URL: http://www.angelikalanger.com/Articles/EffectiveJava/56.GC.G1.Details/56.GC.G1.Details.html |
If you are interested to hear more about this and related topics you might want to check out the following seminar: |
---|
Seminar High-Performance Java - programming, monitoring, profiling, and tuning techniques 4 day seminar (open enrollment and on-site) Garbage Collection Tuning - profiling and tuning of memory related performance issues 1 day seminar (open enrollment and on-site) |