G1 ist der neue Garbage Collector in Java’s VirtualMachine. Im JDK 7 / JRE 7 soll er den noch aktuellen CMS Garage Collector ablösen. Als Grundlage für diesen Artikel empfehle ich meinen Artikel über den CMS GC vom 31.12.2010 zulesen. Der Name G1 steht für “Garbage-First.” Es bezieht sich auf de Grundgedanken von G1 zuerst stark “verunreinigte” Bereiche (Regions) in Ordnung zu bringen.

GCs können folgende keine, eine oder beide Eigenschaften haben:

  • concurrent – parallel zu den Applikationen laufen
  • parallel – mehrere Threads des GC laufen parallel zueinander ab

Grundgedanke

G1 arbeitet parallel und fast concurrent. Er wurde auf Agilität optimiert. Bei der Bereinigung sorgt er für nur sehr kurze Pausen: die stop-the-world genannt werden. Generell verfolgt er die gleiche Intention, wie CMS: der Java Heap wird in Young und Tenured Generation unterteil. Im Detail ist die Umsetzung jedoch sehr verschieden gelöst worden. Die Permanent Generation wurde im Design nicht verändert: sie ist nicht Teil des Heaps. Die konkrete Implementierung der PermGen hat sch jedoch geändert.

Leider gibt es bis jetzt nur wenige und sehr spärlich gehaltene Informationen und Dokumentationen zum neuen GC. Ich hoffe mit dem ersten nicht-englisch-sprachigen Artikel, nach meinen Kenntnisstand, einen Überblick zugeben. Manche Informationen sind allerdings aus früheren Entwicklungsstadien und teilweise sehr wenig detailliert – zum Beispiel weis man vom CMS die prozentuale Aufteilung des Heaps (32:68 YoungGen:Tenured); davon ist mir im Fall G1 noch nichts bekannt. G1 soll vor allem mehrere CPU-Kerne und aktuelle Multi-Thread-Hardware besser ausnutzen können. [4,5,7]

Java Heap: Aufteilung

Der Heap wird nicht mehr in zwei Generations aufgeteilt. Jetzt wird er in n “Region” à 1 MiB gesplittet. Die Regions werden in einem globalen Card Space mit Ein-Byte-Werten markiert. Jedes dieser Regions kann demnach Teil der YoungGen, Eden, From- oder To-Survivor-Spaces, oder der Tenured sein. Daher ist die grundlegende Idee bei G1 und CMS dieselbe. Die Umsetzung wurde nur durch 1-MiB-Regions auf Agilität und Thread-Sicherheit angepasst. So werden sehr kurze Pausen möglich und der GC kann unabhängige Threads al Gusto starten. Dadurch werden unnötige GC-Durchläufe vermieden und die stop-the-world-Pausen minimiert.

Arbeitsweise

G1 unterteilt den gesamten Heap in Region à 1 MiB. Innerhalb einer Region gibt es 512-Byte-große Bereiche: Cards. Diese Cards werden also YoungGen und Tenured markiert. Das Markieren geschieht über die Global Card Tabe. Alle Elemente hierin verweisen auf eine Card. Jeder Eintrag ist Ein-Byte groß. Diese geben an, ob sich der Inhalt der Card geändert hat oder nicht. Daher heißen die Einträgen in der Global Card Tabe auch “Dirty cards.”

Zu jeder Region wird sich ein Wert gemerkt: top oder die “memory barrier.” Sie gibt an ab welcher Stelle die Region gefüllt ist, also ab wo geschrieben werden kann. Jede Region hat zudem ein RS, remembered Set, welches Referenzen außerhalb der Region und deren Änderungen aufzeichnet. Null- und interene Referenzen werden hier nicht berücksichtig.

G1 kümmert sich vorrangig um stark mit “garbage” verunreinigte Region. Die Bewertung nach YoungGen und Tenured findet hierbei ebenfalls statt. Gegebenenfalls wird eine Card in die korrekte Region kopiert, also in Tenured befördert. G1 führt kein direktes Compacting, also Defragmentierung, durch – nur durch Kopieren werden Cards defragmentiert. Das Kopieren benötigt auch den Hauptanteil der Arbeit. Das spätere Ummarkieren fällt kaum ins Gewicht. G1 kann also wesentlich besser auf vielen CPUs laufen. Dazu ist auch durch das Prinzip von Devide and Konquer fast keine Synchronisation notwendig. Zudem lassen sich Pausen wesentlich besser vorhersagen. Kürzer sind diese durch das Aufteilen in Regions auch. [1,6,7]

Achtung

Der G1 ist noch als experimentell eingestuft. Er wird nach jetzigem Stand CMS im Frühjahr, mit Erscheinen des JDK 7, ablösen. Obwohl er sehr weit fortgeschritten und getestet ist ist Vorsicht angebracht. Denn noch ist G1 nicht mit allen Java-Richtlinien konform. Es muss also getestet werden ob G1 in diesem Fall Probleme oder Störungen verursachen kann. Einen Testlauf ist es aber sicherlich wert.

Zudem gibt es bereits Berichte über Crashs durch G1: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6775807. Diese stammen jedoch meistens aus der frühen Entwicklungsphase. [2,8]

G1 testen

Seit dem Java SE 6 Update 14 ist G1 als Test-GC implementiert. Man kann den G1 testen, indem man in der VM des JDK 6 die experimentellen GCs aktiviert und G1 festlegt.

-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

Möchte man als Zielvorgabe nicht länger als 50 ms auf den GC warten gibt man folgende Parameter an:

-XX:MaxGCPauseMillis=50

Um den GC alle 200 ms eine neue Region aufräumen zulassen gibt man folgendes an:

-XX:GCPauseIntervalMillis=200

Leider ist mir noch kein Default-Wert der beiden letzteren Optionen bekannt. Zudem sind sie nicht bindend; der GC versucht es in dieser Zeit zuschauen, garantiert es jedoch nicht. Um Details zu den GC-Durchläufen auf der Konsole zu sehen gibt man folgenden Parameter mit an:

-XX:+PrintGCDetails

[2,3,4,6]

Zusammenfassung

Der G1 sollte durch seine Granularität und die Parallelität in vielen Anwendungsgebieten schneller und effektiver sein als CMS. Somit wird Java 7 auch attraktiver für Echtzeitanwendungen. Allerdings kann er in einigen Fällen auch langsamer sein. Ein Tuning ist, wie im CMS, über die Parameter möglich. Gegenüber dem Parallel-GC, der bereits seit Java 1.5 zur Verfügung steht, wird er sich noch beweisen müssen.

G1 wird sehr viel besser für Echtzeit-Anwendungen als CMS geeignet sein. Zudem ist er besser vorhersagbar. Die Parameter erlauben auch direktere Angabe relevanter Größen – bei CMS musste das über die Heap-Size reguliert werden.

[1] http://tech.puredanger.com/2008/05/09/javaone-g1-garbage-collector/
[2] http://www.oracle.com/technetwork/java/javase/tech/g1-intro-jsp-135488.html
[3] http://www.softcov.com/programming-and-testing/java-garbage-collector-new-g1-in-depth-exploration.html
[4] http://blogs.sun.com/vikram/entry/garbage_first_3_differences_between
[5] http://ajaybiswal.blogspot.com/2010/10/g1garbage-first-vs-cms-garbage.html
[6] http://agents.felk.cvut.cz/wiki/lib/exe/fetch.php?id=teaching%3Aaja&cache=cache&media=teaching:aja3.pdf
[7] http://research.sun.com/jtech/pubs/04-g1-paper-ismm.pdf
[8] http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6775807