114 votes

Comment la concaténation de chaînes est-elle implémentée dans Java 9?

Comme écrit dans JEP 280: Indify de Concaténation de Chaîne:

Modifier la statique String-concaténation du bytecode à la séquence générée par javac utilisation invokedynamic des appels de JDK fonctions de la bibliothèque. Cela permettra à l'avenir optimisations String concaténation sans exiger d'autres changements pour le bytecode emmited en javac.

Ici, je veux comprendre ce que l'utilisation d' invokedynamic des appels est et comment le bytecode de concaténation est différent de invokedynamic?

101voto

T.J. Crowder Points 285826

Le "vieux" chemin de sortie d'un tas d' StringBuilder-opérations orientées. Considérons ce programme:

public class Example {
    public static void main(String[] args)
    {
        String result = args[0] + "-" + args[1] + "-" + args[2];
        System.out.println(result);
    }
}

Si nous compilons qu'avec JDK 8 ou une version antérieure, puis utiliser javap -c Example voir le bytecode, nous voyons quelque chose comme ceci:

public class Exemple {
 Exemple public();
Code:
 0: aload_0
 1: invokespecial #1 // Méthode java/lang/Object."<init>":()V
 4: retour

 public static void main(java.lang.String[]);
Code:
 0: nouvelle #2 // de la classe java/lang/StringBuilder
 3: dup
 4: invokespecial #3 // Méthode java/lang/StringBuilder."<init>":()V
 7: aload_0
 8: iconst_0
 9: aaload
 10: invokevirtual #4 // Méthode java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 13: pma #5 // la Chaîne -
 15: invokevirtual #4 // Méthode java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 18: aload_0
 19: iconst_1
 20: aaload
 21: invokevirtual #4 // Méthode java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 24: pma #5 // la Chaîne -
 26: invokevirtual #4 // Méthode java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 29: aload_0
 30: iconst_2
 31: aaload
 32: invokevirtual #4 // Méthode java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 35: invokevirtual #6 // Méthode java/lang/StringBuilder.toString:()Ljava/lang/String;
 38: astore_1
 39: getstatic #7 // Domaine java/lang/Système.out:Ljava/io/PrintStream;
 42: aload_1
 43: invokevirtual #8 // Méthode java/io/PrintStream.println:(Ljava/lang/String;)V
 46: le retour
}

Comme vous pouvez le voir, il crée un StringBuilder et utilisations append. Ceci est célèbre assez inefficaces comme la valeur par défaut de la capacité de la mémoire tampon intégré en StringBuilder 'est que de 16 caractères, et il n'y a aucun moyen pour le compilateur de savoir à allouer plus à l'avance, de sorte qu'il finit par avoir à réaffecter. C'est aussi un tas d'appels de méthode. (À noter que la JVM peut parfois détecter et de réécrire ces motifs d'appels pour les rendre plus efficaces, cependant).

Regardons ce que Java 9 génère:

public class Exemple {
 Exemple public();
Code:
 0: aload_0
 1: invokespecial #1 // Méthode java/lang/Object."<init>":()V
 4: retour

 public static void main(java.lang.String[]);
Code:
 0: aload_0
 1: iconst_0
 2: aaload
 3: aload_0
 4: iconst_1
 5: aaload
 6: aload_0
 7: iconst_2
 8: aaload
 9: invokedynamic #2, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 14: astore_1
 15: getstatic #3 // Domaine java/lang/Système.out:Ljava/io/PrintStream;
 18: aload_1
 19: invokevirtual #4 // Méthode java/io/PrintStream.println:(Ljava/lang/String;)V
 22: le retour
}

Oh mon dieu mais c'est plus court. :-) Il fait un seul appel à l' makeConcatWithConstants de StringConcatFactory, qui dit ceci dans sa Javadoc:

Méthodes pour faciliter la création de concaténation de Chaîne méthodes, qui peuvent être utilisés efficacement concaténer un nombre connu des arguments de types connus après, éventuellement, le type de l'adaptation et de l'évaluation partielle des arguments. Ces méthodes sont généralement utilisées comme méthodes bootstrap pour invokedynamic sites d'appel, à l'appui de la concaténation de chaîne fonction du Langage de Programmation Java.

23voto

nullpointer Points 1135

Avant d'entrer dans les détails de l' invokedynamic de mise en œuvre utilisés pour l'optimisation de la concaténation de Chaîne, à mon avis, il faut faire un peu de fond sur Ce qui est invokedynamic et comment puis-je l'utiliser?

L' invokedynamic l'instruction simplifie et potentiellement améliore les implémentations de compilateurs et l'exécution des systèmes pour les langages dynamiques sur la JVM. Il le fait en permettant à la langue du maître d'œuvre pour définir personnalisé le couplage comportement avec l' invokedynamic instruction qui consiste à le en suivant les étapes ci-dessous.


Je serais probablement essayer et de vous faire passer à travers ces avec les changements qui ont été apportés pour la mise en œuvre de la concaténation de Chaîne d'optimisation.

  • La définition de la Méthode de démarrage:- Avec Java9, les méthodes bootstrap pour invokedynamic sites d'appel, à l'appui de la concaténation de chaîne principalement makeConcat et makeConcatWithConstants ont été introduites avec l' StringConcatFactory mise en œuvre.

    L'utilisation de invokedynamic offre une alternative pour sélectionner une traduction de la stratégie jusqu'à l'exécution. La stratégie de la traduction utilisée en StringConcatFactory est similaire à l' LambdaMetafactory comme annoncé dans la précédente version de java. En outre, l'un des buts de la PEC mentionné dans la question, pour étirer ces stratégies plus loin.

  • La spécification de la Constante de la Piscine Entrées:- ce sont les statiques supplémentaires des arguments au invokedynamic instruction autre que (1) MethodHandles.Lookup objet qui est une usine pour la méthode de création de poignées dans le contexte de l' invokedynamic enseignement,(2) String objet, le nom de la méthode mentionnée dans l'appel dynamique de site et (3) l' MethodType de l'objet, l'résolu le type de signature de la dynamique de l'appel site.

    Il y a déjà des liens au cours de la liaison du code. Au moment de l'exécution, la méthode de démarrage s'exécute et des liens dans le code réel de faire la concaténation. Il réécrit l' invokedynamic appel avec un invokestatic appel. Cela charge la constante de chaîne à partir de la constante de la piscine, la méthode de démarrage statique args sont un levier pour passer ces et d'autres constantes directement à la méthode du bootstrap appel.

  • À l'aide de la invokedynamic Instruction:- Cette offre d'installations pour un paresseux de liaison, en fournissant les moyens pour l'amorçage de l'appel de la cible une seule fois, lors de la première invocation. L'idée concrète de l'optimisation ici est de remplacer l'ensemble de l' StringBuilder.append danse avec un simple invokedynamic appel à l' java.lang.invoke.StringConcatFactory, qui permettra d'accepter les valeurs de la nécessité de la concaténation.

Le Indify de Concaténation de Chaîne est proposé avec un exemple d'analyse comparative de l'application avec Java9 où une méthode similaire à celle partagée par @T. J. Crowder est compilé et que la différence dans le bytecode est assez visible entre les divers mise en œuvre.

19voto

Eugene Points 6271

Je vais légèrement, ajoutez un peu de détails ici. La partie principale à obtenir, c'est que la façon de concaténation de chaîne se fait est un moteur d'exécution de décision, pas un moment de la compilation, l'un plus. Ainsi, il peut changer, ce qui signifie que vous avez compilé votre code une fois contre java-9 et il peut changer l'implémentation sous-jacente cependant il lui plaît, sans avoir besoin de re-compiler.

Et le deuxième point est que pour le moment il y a 6 possible strategies for concatenation of String:

 private enum Strategy {
    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder}.
     */
    BC_SB,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but trying to estimate the required storage.
     */
    BC_SB_SIZED,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but computing the required storage exactly.
     */
    BC_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also tries to estimate the required storage.
     */
    MH_SB_SIZED,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also estimate the required storage exactly.
     */
    MH_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that constructs its own byte[] array from
     * the arguments. It computes the required storage exactly.
     */
    MH_INLINE_SIZED_EXACT
}

Vous pouvez choisir l'un d'eux par l'intermédiaire d'un paramètre : -Djava.lang.invoke.stringConcat. Notez que StringBuilder est toujours une option.

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