Différence entre les chaînes compactes et les chaînes compressées dans Java 9

Quels sont les avantages des chaînes compactes sur les chaînes compressées dans JDK9?

Les chaînes compressées (Java 6) et les chaînes compactes (Java 9) ont toutes deux la même motivation (les chaînes sont souvent en latin-1, donc la moitié de l’espace est gaspillée) et les objectives (rendent ces chaînes plus petites),

Cordes compressées

Dans une interview, Aleksey Shipilëv (qui était responsable de l’implémentation de la fonctionnalité Java 9) a déclaré ceci à propos des chaînes compressées:

La fonction UseCompressedSsortingngs était plutôt conservasortingce: en distinguant les cas char[] et byte[] et en essayant de compresser le caractère char[] en byte[] dans la construction Ssortingng , la plupart des opérations Ssortingng sur char[] , qui devaient décompresser la Ssortingng. Par conséquent, il n’a bénéficié que d’un type particulier de charges de travail, où la plupart des chaînes sont compressibles (la compression n’est donc pas gâchée), et seules quelques opérations de Ssortingng connues sont effectuées (aucune décompression n’est donc nécessaire). Dans de nombreuses charges de travail, l’activation de -XX:+UseCompressedSsortingngs était une pessimisation.

[…] L’implémentation de UseCompressedSsortingngs était essentiellement une fonctionnalité facultative qui maintenait une implémentation Ssortingng complètement distincte dans alt-rt.jar , qui était chargée une fois que l’option VM était fournie. Les fonctionnalités facultatives sont plus difficiles à tester, car elles doublent le nombre de combinaisons d’options à essayer.

Cordes compactes

En revanche, en Java 9, les chaînes compactes sont entièrement intégrées à la source JDK. Ssortingng est toujours sauvegardée par l’ byte[] , où les caractères utilisent un octet s’ils sont Latin-1 et sinon deux. La plupart des opérations effectuent une vérification pour voir quel est le cas, par exemple charAt :

 public char charAt(int index) { if (isLatin1()) { return SsortingngLatin1.charAt(value, index); } else { return SsortingngUTF16.charAt(value, index); } } 

Les chaînes compactes sont activées par défaut et peuvent être partiellement désactivées – “partiellement” car elles sont toujours sauvegardées par un byte[] et les opérations renvoyant des caractères doivent toujours être regroupées à partir de deux octets distincts (en raison de leur caractère insortingnsèque). a un impact sur la performance).

Plus

Si vous êtes intéressé par plus d’arrière-plan sur les chaînes compactes, je vous recommande de lire l’interview à laquelle j’ai lié ci-dessus et / ou de regarder ce super discours du même Aleksey Shipilëv (qui explique également la nouvelle concaténation de chaînes).

XX: + UseCompressedSsortingngs et Compact Ssortingngs sont des choses différentes.

UseCompressedSsortingngs signifiait que les chaînes uniquement en ASCII pouvaient être converties en byte[] , mais que cette option était désactivée par défaut. Dans jdk-9, cette optimisation est toujours activée, mais pas via l’indicateur lui-même, mais intégré.

Jusqu’à ce que les chaînes java-9 soient stockées en interne sous la forme d’un caractère char[] en codage UTF-16. À partir de java-9 et plus, ils seront stockés en tant byte[] . Pourquoi?

Parce que dans ISO_LATIN_1 chaque caractère peut être codé en un seul octet (8 bits) par rapport à ce qu’il est jusqu’à présent (16 bits, 8 de chaque étant utilisé). Cela ne fonctionne que pour ISO_LATIN_1 , mais c’est la majorité des chaînes utilisées de toute façon.

Donc, c’est fait pour l’utilisation de l’espace.

Voici un petit exemple qui devrait rendre les choses plus claires:

 class SsortingngCharVsByte { public static void main(Ssortingng[] args) { Ssortingng first = "first"; Ssortingng russianFirst = "первыи"; char[] c1 = first.toCharArray(); char[] c2 = russianFirst.toCharArray(); for (char c : c1) { System.out.println(c >>> 8); } for (char c : c2) { System.out.println(c >>> 8); } } } 

Dans le premier cas, nous allons obtenir des zéros uniquement, ce qui signifie que les 8 bits les plus significatifs sont des zéros; dans le second cas, il y aura une valeur non nulle, ce qui signifie qu’au moins un bit du plus significatif 8 est présent.

Cela signifie que si nous stockons en interne des chaînes sous forme de tableau de caractères, il existe des chaînes littérales qui gaspillent en réalité la moitié de chaque caractère. Il se trouve que de nombreuses applications gaspillent beaucoup d’espace à cause de cela.

Vous avez une chaîne composée de 10 caractères Latin1? Vous venez de perdre 80 bits, soit 10 octets. Pour atténuer cette compression de chaîne a été faite. Et maintenant, il n’y aura pas de perte d’espace pour ces cordes.

En interne, cela signifie également de très belles choses. Pour distinguer entre les chaînes LATIN1 et UTF-16 il existe un coder champ:

 /** * The identifier of the encoding used to encode the bytes in * {@code value}. The supported values in this implementation are * * LATIN1 * UTF16 * * @implNote This field is trusted by the VM, and is a subject to * constant folding if Ssortingng instance is constant. Overwriting this * field after construction will cause problems. */ private final byte coder; 

Maintenant basé sur cette length est calculé différemment:

 public int length() { return value.length >> coder(); } 

Si notre chaîne est Latin1 uniquement, le codeur sera zéro, donc la longueur de la valeur (le tableau d’octets) est la taille des caractères. Pour les non-Latin1, divisez par deux.

Compact Ssortingngs aura le meilleur des deux mondes.

Comme on peut le voir dans la définition fournie dans la documentation OpenJDK:

La nouvelle classe Ssortingng stockera les caractères codés ISO-8859-1 / Latin-1 (un octet par caractère) ou UTF-16 (deux octets par caractère), en fonction du contenu de la chaîne. L’indicateur de codage indiquera quel codage est utilisé.

Comme mentionné par @Eugene, la plupart des chaînes sont codées au format Latin-1 et requièrent un octet par caractère. Par conséquent, elles ne requièrent pas l’intégralité de l’espace de 2 octets dans l’implémentation de la classe Ssortingng actuelle.

L’implémentation de la nouvelle classe Ssortingng passera du UTF-16 char array de UTF-16 char array à a byte array plus un champ d’indicateur de codage . Le champ d’encodage supplémentaire indique si les caractères sont stockés au format UTF-16 ou Latin-1.

Cela conclut également que nous pourrons également stocker des chaînes au format UTF-16 si nécessaire. Et cela devient aussi le principal sharepoint différence entre la chaîne compressée de Java 6 et la chaîne compacte de Java 9, car dans la chaîne compressée, seul le tableau d’octets [] était utilisé pour le stockage, qui était alors représenté sous forme de code ASCII pur .

Chaînes compressées (-XX: + UseCompressedSsortingngs)

Cette fonctionnalité facultative a été introduite dans Java 6 Update 21 pour améliorer les performances de SPECjbb en codant uniquement la chaîne US-ASCII sur un octet par caractère.

Cette fonctionnalité peut être activée par un indicateur -XX:+UseCompressedSsortingngs ( -XX:+UseCompressedSsortingngs ). Quand il est activé, Ssortingng.value été changé en référence à un object et pointe vers un byte[] , pour les chaînes contenant uniquement des caractères US-ASCII de 7 bits, ou bien un caractère char[] .

Plus tard, il a été supprimé dans Java 7 en raison de son niveau élevé de maintenance et de sa difficulté à tester.

Chaîne compacte

Ceci est une nouvelle fonctionnalité introduite dans Java 9 pour construire une chaîne efficace en mémoire.

Avant Java 9, la classe Ssortingng stockait des caractères dans un tableau de caractères, en utilisant deux octets pour chaque caractère mais à partir de Java 9, la nouvelle classe Ssortingng stockait des caractères en byte[] un (octet par caractère) ou char[] (deux octets par caractère). ), en fonction du contenu de la chaîne, plus un champ d’indicateur de codage. Si les caractères de type Ssortingng sont de type Latin-1 byte[] sera utilisé si les caractères sont de type UTF-16 alors le caractère char[] sera utilisé. L’indicateur de codage indiquera quel codage est utilisé.