Anleitung zum Java-String-Pool

1. Überblick

Das String -Objekt ist die am häufigsten verwendete Klasse in der Java-Sprache.

In diesem kurzen Artikel untersuchen wir den Java-String-Pool - den speziellen Speicherbereich, in dem Strings von der JVM gespeichert werden.

2. String Interning

Dank der Unveränderlichkeit von Strings in Java kann die JVM die für sie zugewiesene Speichermenge optimieren, indem sie nur eine Kopie jedes Literal String im Pool speichert . Dieser Prozess wird interning genannt.

Wenn wir eine String -Variable erstellen und dieser einen Wert zuweisen, durchsucht die JVM den Pool nach einem String mit gleichem Wert.

Wenn gefunden, gibt der Java-Compiler einfach einen Verweis auf seine Speicheradresse zurück, ohne zusätzlichen Speicher zuzuweisen. **

Wird er nicht gefunden, wird er dem Pool hinzugefügt (interniert) und seine Referenz wird zurückgegeben.

Schreiben wir einen kleinen Test, um das zu überprüfen:

String constantString1 = "Baeldung";
String constantString2 = "Baeldung";

assertThat(constantString1)
  .isSameAs(constantString2);

3. Strings mit dem Konstruktor zugewiesen

Wenn Sie mit dem Operator new einen String erstellen, erstellt der Java-Compiler ein neues Objekt und speichert es in dem für die JVM reservierten Heap-Bereich.

Jeder so erstellte String zeigt auf einen anderen Speicherbereich mit eigener Adresse.

Mal sehen, wie sich das vom vorherigen Fall unterscheidet:

String constantString = "Baeldung";
String newString = new String("Baeldung");

assertThat(constantString).isNotSameAs(newString);

4. String Literal vs String Object

  • Wenn Sie ein String -Objekt mit dem Operator new () erstellen, wird immer ein neues Objekt im Heap-Speicher erstellt. Wenn wir hingegen ein Objekt mit String -Literal-Syntax erstellen, z. "Meldung" kann ein vorhandenes Objekt aus dem String-Pool zurückgeben, sofern es bereits vorhanden ist. ** Andernfalls wird ein neues String-Objekt erstellt und zur späteren Wiederverwendung in den String-Pool gestellt.

Auf einer höheren Ebene sind beide String -Objekte, der Hauptunterschied besteht jedoch darin, dass der new () -Operator immer ein neues String -Objekt erstellt. Wenn Sie einen String mit einem Literal erstellen, ist dies intern.

Dies wird viel deutlicher, wenn wir zwei String -Objekte vergleichen, die mit dem String -Literal und dem new -Operator erstellt wurden:

String first = "Baeldung";
String second = "Baeldung";
System.out.println(first == second);//True

In diesem Beispiel haben die String -Objekte dieselbe Referenz.

Als Nächstes erstellen wir zwei verschiedene Objekte mit new und prüfen, ob sie unterschiedliche Referenzen haben:

String third = new String("Baeldung");
String fourth = new String("Baeldung");
System.out.println(third == fourth);//False

Wenn Sie ein String -Literal mit einem String -Objekt vergleichen, das mit dem Operator new () mit dem Operator == erstellt wurde, wird in ähnlicher Weise false:

String fifth = "Baeldung";
String sixth = new String("Baeldung");
System.out.println(fifth == sixth);//False

Im Allgemeinen sollten wir, wenn möglich, die String -Schreibweise verwenden.

Es ist einfacher zu lesen und gibt dem Compiler die Möglichkeit, unseren Code zu optimieren.

5. Manuelle Internierung

Wir können einen String im Java-String-Pool manuell intern machen, indem wir die intern () -Methode für das Objekt aufrufen, das wir intern verwenden möchten.

Durch manuelles Internieren des String wird seine Referenz im Pool gespeichert und die JVM gibt diese Referenz bei Bedarf zurück.

Erstellen wir dazu einen Testfall:

String constantString = "interned Baeldung";
String newString = new String("interned Baeldung");

assertThat(constantString).isNotSameAs(newString);

String internedString = newString.intern();

assertThat(constantString)
  .isSameAs(internedString);

6. Müllsammlung

Vor Java 7 hat die JVM den Java-String-Pool in den PermGen -Space gestellt, der eine feste Größe hat - sie kann zur Laufzeit nicht erweitert werden und ist für die Garbage Collection nicht geeignet.

Das Risiko, Strings in PermGen (anstelle von Heap ) zu internieren, besteht darin, dass wir einen OutOfMemory -Fehler von der JVM erhalten können, wenn wir zu viele Strings internieren.

Ab Java 7 wird der Java-String-Pool im Heap -Space gespeichert. Dies ist ein von der JVM _. gesammelter Müll. Der Vorteil dieses Ansatzes ist das geringere Risiko eines OutOfMemory -Fehlers ** , da nicht referenzierte Strings_ aus dem Pool entfernt werden , wodurch der Speicher freigegeben wird.

7. Leistung und Optimierungen

In Java 6 besteht die einzige Optimierung darin, den PermGen -Space während des Programmaufrufs mit der JMM-Option MaxPermSize zu vergrößern:

-XX:MaxPermSize=1G

In Java 7 haben wir detailliertere Optionen zum Untersuchen und Erweitern/Reduzieren der Poolgröße. Sehen wir uns die zwei Optionen zur Anzeige der Poolgröße an:

-XX:+PrintFlagsFinal
-XX:+PrintStringTableStatistics

Die Standardpoolgröße ist 1009. Wenn Sie die Poolgröße erhöhen möchten, können Sie die JSM-Option StringTableSize verwenden:

-XX:StringTableSize=4901
  • Beachten Sie, dass das Erhöhen der Poolgröße mehr Speicher benötigt, jedoch den Zeitaufwand für das Einfügen der Strings in die Tabelle verringert. **

8. Ein Hinweis zu Java 9

Bis Java 8 wurden Strings intern als Array von Zeichen dargestellt - char[] , die in UTF-16 codiert sind, so dass jedes Zeichen zwei Byte Speicher benötigt.

Mit Java 9 wird eine neue Repräsentation mit dem Namen Compact Strings zur Verfügung gestellt. Dieses neue Format wählt abhängig vom gespeicherten Inhalt die geeignete Kodierung zwischen char[] ​​und byte[]__.

Da die neue String -Repräsentation die UTF-16 -Kodierung nur bei Bedarf verwendet, ist die Menge des heap -Speichers erheblich geringer, was wiederum zu weniger Garbage Collector -Overhead auf dem JVM.

9. Fazit

In diesem Handbuch haben wir gezeigt, wie die JVM und der Java-Compiler die Speicherzuordnung für String -Objekte über den Java String Pool optimieren.

Alle in diesem Artikel verwendeten Codebeispiele sind verfügbar unter https://github.com/eugenp/tutorials/tree/master/java-strings Über Github