String deduplication

String Deduplication – ein neues Feature des Garbage Collectors G1

Mit Java 7 Update 9 hat Oracle erstmals eine Java Virtual Machine mit dem Garbage Collector G1 (“Garbage First”) ausgeliefert. Nach einer langen Testphase soll der G1 zum Standard-Garbage-Collector in Java 9 werden. Durch ein ausgefeiltes Speichermanagement mit kleinen Speicherblöcken verspricht der G1 kürzere Pausenzeiten als die bisher bei den Oracle-VMs verwendeten Garbage-Collectoren.
In der Testphase blieb der G1 zunächst inaktiv und konnte über die VM-Option -XX:+UseG1GC eingeschaltet werden.

String Deduplication ab Java 8 Update 20

Mit dem Java 8 Update 20 wurde der G1 um ein interessantes neues Feature erweitert: Die Deduplizierung von String-Objekten (“String Deduplication”). Damit soll der Speicherverbrauch einer Anwendung deutlich reduziert werden, indem identische Zeichenketten nur einmal gespeichert werden müssen und Duplikate vom G1 entfernt werden.

Um zu verstehen, wie dieses Feature im Detail funktioniert sind vertiefende  Kenntnisse der String-Klasse notwendig. Die String-Klasse benutzt als Datencontainer für eine Zeichenkette ein Array vom Typ char:

private final char value[];

Die Idee der String Deduplication ist, diese Arrays bei gleichem Inhalt zusammenzufassen und auf diese Art Speicherplatz einzusparen. Wie geht der G1 dabei vor?

String Deduplication vorher
String Deduplication vorher

String-Objekte werden zur Laufzeit eines Java-Programms auf dem Heap angelegt. Dabei können Instanzen entstehen, deren value-Arrays gleich lang sind und gleichen Inhalt haben. Um diese Instanzen zu finden, fügt der G1 bei der Garbage Collection String-Instanzen nach einem bestimmten Muster in eine Warteschlange ein, die in einem separaten Thread abgearbeitet werden. In diesem Thread wird für jede enthaltene String-Instanz durch eine Hashtable geprüft, ob bereits ein String mit dem gleichen value-Array bekannt ist. Ist dies der Fall, bekommt das value-Attribut der Instanz den Wert des value-Attributs aus dem bereits in der Hashtable enthaltenen String. Beide String-Instanzen referenzieren damit das selbe Array von char-Werten.

String Deduplication nachher
String Deduplication nachher

Damit kann im Beispiel ein char-Array der Länge 10, also ein Speicherblock von 20 Bytes Größe, wieder freigegeben werden.

Aktivieren der String Deduplication

Wie jede Optimierung ist auch die String Deduplication eine Tradeoff-Optimierung: Zur Durchführung werden zusätzliche Ressourcen eingesetzt. In diesem Fall sind das:

  • Rechenzeit für den deduplizierenden Thread
  • Speicherplatz für die Hashtable, mit der die Kandidaten für die Deduplizierung gefunden werden.

Da sich die Optimierung nicht in jedem Fall lohnt, ist die String Deduplication zunächst deaktiviert. Um sie einzuschalten, kann man beim Start der JVM die Option -XX:+UseStringDeduplication angeben. Um zu ermitteln, welchen Erfolg die String Deduplication bringt, ist die Option -XX:+PrintStringDeduplicationStatistics hilfreich. (Zur Erinnerung: String Deduplication funktioniert nur mit dem Garbage Collector G1. Bis zum Erscheinen von Java 9 ist also zusätzlich die VM-Option -XX:+UseG1GC notwendig.)

Und was ist mit String Interning?

Java besitzt schon immer einen Mechanismus zur Kanonisierung von String-Objekten, nämlich das sogenannte Interning. Dieses Verfahren wird automatisch vom Klassenlader verwendet, um String-Literale zusammenzufassen. Auch der Entwickler könnte ein String-Objekt durch Aufruf der Methode intern() explizit kanonisieren.
Die durch intern() kanonisierten String-Objekte werden aber im sogenannten Runtime Constant Pool gespeichert. Da dieser Speicherbereich bis einschließlich Java 7 recht knapp bemessen war und eine Garbage Collection nicht garantiert war, hat Oracle vor der expliziten Verwendung von intern() durch den Entwickler abgeraten.
Zwei weitere Gründe sprechen gegen das String Interning:

  • Es ist in vielen Anwendungsfällen schwierig zu erkennen, ob String Interning aussichtsreich ist.
  • String Interning nutzt die Rechenzeit des Anwendungsthreads. Das bedeutet: Das Anwendungsprogramm hat mehr zu tun – egal, ob die zusätzlich investierte Arbeit etwas bringt oder nicht.

String Deduplication löst beide Probleme: Der Anwendungsthread wird nicht belastet, da die Deduplizierung in einem weiteren Thread stattfindet. Außerdem werden einfach alle String-Instanzen in Betracht gezogen – der Erfolg hängt also nicht von der Kompetenz des Entwicklers ab.

Fazit String Deduplication

Mit der String Deduplication bringt Java 9 ein spannendes neues Feature, das den Memory-Footprint bei vielen Java-Programmen deutlich reduzieren kann. Die Funktionalität braucht dabei lediglich beim Start der VM aktiviert zu werden; eine Änderung des Anwendungsprogramms ist nicht notwendig.

Seminare zu String Deduplication

Weiterlesen