Guide du pool de chaînes Java

Guide du pool de chaînes Java

1. Vue d'ensemble

L'objetString est la classe la plus utilisée dans le langage Java.

Dans cet article rapide, nous allons explorer le pool de chaînes Java -the special memory region where Strings are stored by the JVM.

2. Stage de chaîne

Grâce à l'immuabilité deStrings en Java, la JVM peut optimiser la quantité de mémoire qui leur est allouée destoring only one copy of each literal String in the pool. Ce processus s'appelleinterning.

Lorsque nous créons une variableString et lui attribuons une valeur, la JVM recherche dans le pool unString de valeur égale.

S'il est trouvé, le compilateur Java renverra simplement une référence à son adresse mémoire, sans allouer de mémoire supplémentaire.

S'il ne le trouve pas, il sera ajouté au pool (interné) et sa référence sera renvoyée.

Écrivons un petit test pour vérifier ceci:

String constantString1 = "example";
String constantString2 = "example";

assertThat(constantString1)
  .isSameAs(constantString2);

3. Strings alloué à l'aide du constructeur

Lorsque nous créons unString via l'opérateurnew, le compilateur Java crée un nouvel objet et le stocke dans l'espace de tas réservé à la JVM.

ChaqueString créé comme ceci pointera vers une région mémoire différente avec sa propre adresse.

Voyons en quoi cela diffère du cas précédent:

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

assertThat(constantString).isNotSameAs(newString);

4. String Littéral vsString Object

When we create a String object using the new() operator, it always creates a new object in heap memory. On the other hand, if we create an object using String literal syntax e.g. “example”, it may return an existing object from the String pool, if it already exists. Sinon, il créera un nouvel objet String et le placera dans le pool de chaînes pour une future réutilisation.

À un niveau élevé, les deux sont les objetsString, mais la principale différence vient du fait que l'opérateurnew() crée toujours un nouvel objetString. De plus, lorsque nous créons unString en utilisant un littéral, il est interné.

Ce sera beaucoup plus clair lorsque nous comparons deux objetsString créés à l'aide du littéralString et de l'opérateurnew:

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

Dans cet exemple, les objetsString auront la même référence.

Ensuite, créons deux objets différents à l'aide denew et vérifions qu'ils ont des références différentes:

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

De même, lorsque nous comparons un littéralString avec un objetString créé à l'aide de l'opérateurnew() en utilisant l'opérateur ==, il retournerafalse:

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

En général,we should use the String literal notation when possible. Il est plus facile à lire et donne au compilateur une chance d’optimiser notre code.

5. Stage manuel

Nous pouvons manuellement interner unString dans le pool de chaînes Java en appelant la méthodeintern() sur l'objet que nous voulons interner.

L'internement manuel duString stockera sa référence dans le pool et la JVM retournera cette référence si nécessaire.

Créons un scénario de test pour ceci:

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

assertThat(constantString).isNotSameAs(newString);

String internedString = newString.intern();

assertThat(constantString)
  .isSameAs(internedString);

6. Collecte des ordures

Avant Java 7, les fichiers JVMplaced the Java String Pool in the PermGen space, which has a fixed size — it can’t be expanded at runtime and is not eligible for garbage collection.

Le risque d'internerStrings dans lesPermGen (au lieu desHeap) est quewe can get an OutOfMemory error de la JVM si nous internons trop deStrings.

À partir de Java 7, le pool de chaînes Java eststored in the Heap space, which is garbage collected par la JVM. L'avantage de cette approche est lereduced risk of OutOfMemory error car lesStrings non référencés seront supprimés du pool, libérer de la mémoire.

7. Performances et optimisations

Dans Java 6, la seule optimisation que nous pouvons effectuer est d'augmenter l'espacePermGen lors de l'appel du programme avec l'option JVMMaxPermSize:

-XX:MaxPermSize=1G

En Java 7, nous disposons d'options plus détaillées pour examiner et développer / réduire la taille du pool. Voyons les deux options pour afficher la taille de la piscine:

-XX:+PrintFlagsFinal
-XX:+PrintStringTableStatistics

Si nous voulons augmenter la taille du pool en termes de buckets, nous pouvons utiliser l'option JVMStringTableSize:

-XX:StringTableSize=4901

Avant Java 7u40, la taille de pool par défaut était de 1009 compartiments, mais cette valeur était sujette à quelques modifications dans les versions Java plus récentes. Pour être précis, la taille de pool par défaut de Java 7u40 à Java 11 était de 60013 et passe à 65536.

Notez que l'augmentation de la taille du pool consommera plus de mémoire mais présente l'avantage de réduire le temps nécessaire pour insérer lesStrings dans la table.

8. Remarque sur Java 9

Jusqu'à Java 8, lesStrings étaient représentés en interne sous la forme d'un tableau de caractères -char[], codés enUTF-16, de sorte que chaque caractère utilise deux octets de mémoire.

Avec Java 9, une nouvelle représentation est fournie, appeléeCompact Strings.. Ce nouveau format choisira l'encodage approprié entrechar[] etbyte[] en fonction du contenu stocké.

Étant donné que la nouvelle représentationString n'utilisera le codageUTF-16 que lorsque cela est nécessaire, la quantité de mémoireheap sera nettement inférieure, ce qui entraînera moins de frais généraux deGarbage Collector sur leJVM.

9. Conclusion

Dans ce guide, nous avons montré comment la JVM et le compilateur Java optimisent les allocations de mémoire pour les objetsString via le pool de chaînes Java.

Tous les exemples de code utilisés dans l'article sont disponiblesover on GitHub.