java -XX:+UseCompressedOops

von Hubert Schmid vom 2013-03-31

Viele Entwickler kennen die Situation: Java-Anwendungen benötigen in Laufzeitumgebungen mit 64-Bit deutlich mehr Hauptspeicher als in solchen mit 32-Bit. Dabei unterscheidet die beiden Welten praktisch nur die Größe der Speicheradressen – beziehungsweise der Referenzen in Java-Sprechweise. Häufig wird jedoch unterschätzt, wie viele Referenzen es typischerweise in einer Anwendung gibt, und welchen Anteil am gesamten Speicherbedarf sie ausmachen.

Offensichtlich muss es für jedes Objekt mindestens eine Referenz geben, die auf dieses Objekt verweist. Denn nicht referenzierte Objekte werden von der automatischen Speicherbereinigung beseitigt. Tatsächlich liegt der Anteil aber deutlich höher, da viele Objekte von mehreren Stellen referenziert werden. Die main-Methode im folgenden Beispiel erzeugt beispielsweise 100 Millionen Objekte und legt sie in einem TreeSet ab, wo für die interne Repräsentation nochmals 100 Millionen Objekte erzeugt werden. Für die Verknüpfung der Objekte werden dagegen 500 Millionen Referenzen benötigt.

import java.util.Set; import java.util.TreeSet; public class TestCompressedOops { public static void main(String... args) { Set<Integer> set = new TreeSet<>(); for (int i = 0; i < 100000000; ++i) { set.add(Integer.valueOf(i)); } } }

Um den Speicherverbrauch der Referenzen in 64-Bit Laufzeitumgebungen zu adressieren, gibt es seit Java 6 den Kommandozeilenschalter -XX:+UseCompressedOops, der seit Java 7 in der Voreinstellung aktiviert ist. Mit dieser Option werden für Referenzen auch in 64-Bit Umgebungen nur 32 Bit verwendet, die allerdings so kodiert sind, dass sich 32 GB statt nur 4 GB Speicher adressieren lassen.

# with optimized references java -XX:+UseCompressedOops TestCompressedOops # without optimized references java -XX:-UseCompressedOops TestCompressedOops

Der Schalter zeigt Wirkung: Das obige Beispiel benötigt auf meinem Rechner mit der Optimierung 35 Prozent weniger Hauptspeicher als ohne die Optimierung – bei praktisch gleichem CPU-Verbrauch. Das ist ein vergleichsweise hoher Wert. In anderen Beispielen schwankt die Einsparung zwischen 20 und 40 Prozent. Also auf zum Speichersparen – falls man an Hauptspeicher gespart hat.