67 votes

Différence entre les chaînes de caractères compactes et les chaînes de caractères compressées en Java 9

Quels sont les avantages de cordes compactes sur des chaînes de caractères compressées dans le JDK9 ?

9 votes

Jamais entendu parler de comprimé les chaînes de caractères (en tant que chose), mais il existe un JEP sur les chaînes de caractères compactes : Cordes compactes .

6 votes

Eh bien, regardez-le maintenant :D Mais, c'est toujours aide pour indiquer où vous avez lu quelque chose.

74voto

Nicolai Points 17516

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 effectivement en Latin-1, ce qui fait perdre la moitié de l'espace) et le même objectif (rendre ces chaînes plus petites) mais les implémentations diffèrent beaucoup.

Cordes comprimées

En une interview Aleksey Shipilëv (qui était chargé de la mise en œuvre de la fonctionnalité Java 9) a déclaré ceci à propos des chaînes compressées :

La fonction UseCompressedStrings était plutôt conservatrice : tout en faisant la distinction entre char[] y byte[] de l'affaire, et en essayant de compresser le char[] en byte[] en String construction, il a fait le plus String les opérations sur char[] qui nécessite de déballer le String. Par conséquent, il n'a bénéficié qu'à un type particulier de charges de travail, où la plupart des chaînes de caractères sont compressibles (de sorte que la compression ne soit pas gaspillée), et où seule une quantité limitée de chaînes de caractères connues est utilisée. String sont effectuées sur eux (donc aucun déballage n'est nécessaire). Dans de très nombreuses charges de travail, l'activation de -XX:+UseCompressedStrings était une pessimisation.

[...] L'implémentation de UseCompressedStrings était essentiellement une fonctionnalité optionnelle qui maintenait un système de gestion de l'information complètement distinct. String la mise en œuvre dans alt-rt.jar qui a été chargé une fois que l'option VM a été fournie. Les fonctionnalités optionnelles sont plus difficiles à tester, car elles doublent le nombre de combinaisons d'options à essayer.

Cordes compactes

En revanche, dans Java 9, les chaînes compactes sont entièrement intégrées dans la source du JDK. String es toujours soutenu par byte[] où les caractères utilisent un octet s'ils sont en Latin-1 et deux sinon. La plupart des opérations vérifient si c'est bien le cas, par ex. charAt :

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

Les chaînes compactes sont activées par défaut et peuvent être partiellement désactivées - "partiellement" parce qu'elles sont toujours soutenues par une chaîne de caractères. byte[] et les opérations de retour char doivent encore les assembler à partir de deux octets distincts (en raison des intrinsèques, il est difficile de dire si cela a un impact sur les performances).

Plus de

Si vous souhaitez en savoir plus sur les cordes compactes, je vous recommande de lire l'entretien J'ai fait le lien ci-dessus et/ou regarder cette grande conférence du même Aleksey Shipilëv (ce qui explique également la nouvelle concaténation des chaînes de caractères).

1 votes

Les performances sont aussi bonnes qu'avant. Dans son exposé, Aleksey parle de charAt par exemple et dit que beaucoup de logiciels (même en interne) dépendent de la vitesse de charAt donc ils ont fait en sorte que ce soit précis.

2 votes

Dans cette section, il parle de performances asymptotiques, c'est-à-dire qu'il ne s'agit pas de passer d'un temps constant à un temps linéaire. Une augmentation constante remplirait ce critère et au moins le code non-instrinsèque montre cette caractéristique parce qu'il doit décaler et or quelques octets.

4 votes

...On pourrait penser qu'ils auraient simplement changé l'encodage interne en UTF-8 et que ce serait terminé... Mais non, ils ont dû rendre les choses difficiles et confuses.

27voto

Eugene Points 6271

XX:+UseCompressedStrings y Cordes compactes sont des choses différentes.

UseCompressedStrings signifie que les chaînes de caractères qui sont uniquement ASCII peuvent être converties en byte[] mais elle était désactivée par défaut. Dans jdk-9, cette optimisation est toujours activée, mais pas via le drapeau lui-même, mais par défaut.

Jusqu'à java-9, les chaînes de caractères sont stockées en interne sous la forme d'un fichier char[] en encodage UTF-16. À partir de java-9, ils seront stockés en tant que byte[] . Pourquoi ?

Parce que dans ISO_LATIN_1 chaque caractère peut être encodé dans un seul octet (8 bits) au lieu de ce qu'il était jusqu'à présent (16 bits, dont 8 ne sont jamais utilisés). Cela fonctionne uniquement para ISO_LATIN_1 mais c'est la majorité des cordes utilisées de toute façon.

C'est donc fait pour l'utilisation de l'espace.

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

class StringCharVsByte {
    public static void main(String[] args) {
        String first = "first";
        String 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 n'aurons que des zéros, 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 des 8 bits les plus significatifs est présent.

Cela signifie que si, en interne, nous stockons les chaînes de caractères sous la forme d'un tableau de caractères, il existe des chaînes de caractères qui gaspillent en fait la moitié de chaque caractère. Il s'avère qu'il existe de nombreuses applications qui gaspillent beaucoup d'espace à cause de cela.

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

En interne, cela signifie également des choses très intéressantes. Pour distinguer les chaînes qui sont LATIN1 y UTF-16 il y a un champ coder :

/**
 * 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 String instance is constant. Overwriting this
 * field after construction will cause problems.
 */
private final byte coder;

Maintenant, sur la base de ce length est calculée différemment :

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

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

6voto

Dhaval Simaria Points 838

Cordes compactes aura le meilleur des deux mondes.

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

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

Comme l'a mentionné @Eugene, la plupart des chaînes de caractères sont codées au format latin-1 et nécessitent un octet par caractère. Elles n'ont donc pas besoin de l'espace complet de 2 octets fourni par la mise en œuvre actuelle de la classe String.

L'implémentation de la nouvelle classe String passera de UTF-16 char array a a byte array plus un champ de drapeau d'encodage . Le supplément champ de codage indique si les caractères sont stockés au format UTF-16 ou Latin-1.

Cela signifie également que nous serons en mesure de stocker des chaînes de caractères au format UTF-16 si nécessaire. Et cela devient également le principal point de différence entre le module Chaîne comprimée de Java 6 y Chaîne compacte de Java 9 dans le mot Compressed String seulement un tableau d'octets[] a été utilisé pour le stockage qui a ensuite été représenté comme ASCII pur .

0voto

Mohit Tyagi Points 1684

Cordes comprimées (-XX:+UseCompressedStrings)

Il s'agissait d'une fonctionnalité facultative introduite dans Java 6 Mise à jour 21 pour améliorer SPECjbb performances en codant uniquement les chaînes US-ASCII sur un octet par caractère.

Cette fonction peut être activée par un -XX drapeau ( -XX:+UseCompressedStrings ). Lorsqu'il est activé, String.value a été transformé en une référence d'objet et pointerait soit vers un fichier byte[] pour les chaînes de caractères ne contenant que des caractères US-ASCII de 7 bits, ou bien un symbole char[] .

Plus tard, il a été supprimé dans Java 7 en raison de sa maintenance élevée et de sa difficulté à être testé.

String compact

Il s'agit d'une nouvelle fonctionnalité introduite dans Java 9 pour construire un String efficace en mémoire.

Avant Java 9, la classe String stockait les caractères dans un tableau de caractères, utilisant deux octets pour chaque caractère, mais à partir de Java 9, la nouvelle classe String stocke les caractères dans un tableau de caractères. byte[] (un octet par caractère) ou char[] (deux octets par caractère), sur la base du contenu de la chaîne, plus un champ de drapeau d'encodage. Si les caractères de la chaîne sont de type Latin-1 puis byte[] sera utilisé autrement si les caractères sont de type UTF-16 puis char[] sera utilisé. L'indicateur d'encodage indique quel encodage est utilisé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X