Comme écrit dans JEP 280: Indify String Concatenation :
Modifiez la
String
séquence de bytecode -concatenation statique générée parjavac
pour utiliser lesinvokedynamic
appels aux fonctions de la bibliothèque JDK. Cela permettra des optimisations futures de laString
concaténation sans nécessiter de modifications supplémentaires du bytecode émis parjavac
.
Ici, je veux comprendre ce qu'est l'utilisation des invokedynamic
appels et en quoi la concaténation de bytecode est différente de invokedynamic
?
java
string
string-concatenation
java-9
invokedynamic
Mohit Tyagi
la source
la source
Réponses:
L '«ancienne» méthode produit un tas d'
StringBuilder
opérations orientées. Considérez ce programme:Si nous compilons cela avec JDK 8 ou une version antérieure et que nous utilisons ensuite
javap -c Example
pour voir le bytecode, nous voyons quelque chose comme ceci:Comme vous pouvez le voir, il crée un
StringBuilder
et utiliseappend
. Ceci est réputé assez inefficace car la capacité par défaut du tampon intégréStringBuilder
n'est que de 16 caractères, et il n'y a aucun moyen pour le compilateur de savoir d'allouer plus à l'avance, donc il finit par devoir réallouer. C'est aussi un tas d'appels de méthode. (Notez que la JVM peut parfois détecter et réécrire ces modèles d'appels pour les rendre plus efficaces, cependant.)Regardons ce que génère Java 9:
Oh mon mais c'est plus court. :-) Il fait un seul appel à
makeConcatWithConstants
fromStringConcatFactory
, qui dit ceci dans son Javadoc:la source
+=
dans sa boucle for. Je leur ai dit que cela dépendait, mais n'oublions pas qu'ils pourraient trouver un meilleur moyen d'enchaîner le concat un jour plus tard. La ligne clé est vraiment l'avant-dernière ligne:So by being smart, you have caused a performance hit when Java got smarter than you.
invokedynamic
permet de choisir différentes stratégies de concaténation au moment de l'exécution et de les relier lors du premier appel, sans la surcharge d'un appel de méthode et d'une table de répartition à chaque appel; plus dans l' article de nicolai ici et dans le JEP .Object
, mais alors vous devriez boxer tous les primitifs ... (Ce que Nicolai couvre dans son excellent article, btw.)String.concat(String)
méthode déjà existante dont l'implémentation crée le tableau de la chaîne résultante sur place. L'avantage devient sans objet lorsque nous devons invoquertoString()
sur des objets arbitraires. De même, lors de l'appel d'une méthode acceptant un tableau, l'appelant doit créer et remplir le tableau, ce qui réduit l'avantage global. Mais maintenant, ce n'est pas pertinent, car la nouvelle solution est essentiellement ce que vous envisagiez, sauf qu'elle n'a pas de surcharge de boxe, ne nécessite pas de création de tableau et que le backend peut générer des gestionnaires optimisés pour des scénarios particuliers.Avant d'entrer dans les détails de l'
invokedynamic
implémentation utilisée pour l'optimisation de la concaténation de chaînes, à mon avis, il faut se familiariser avec ce qui est invokedynamic et comment l'utiliser?J'essaierais probablement de vous expliquer les changements apportés pour l'implémentation de l'optimisation de la concaténation de chaînes.
Définition de la méthode Bootstrap : - Avec Java9, les méthodes bootstrap pour
invokedynamic
les sites d'appel, pour prendre en charge la concaténation de chaînes principalementmakeConcat
etmakeConcatWithConstants
ont été introduites avec l'StringConcatFactory
implémentation.L'utilisation de invokedynamic offre une alternative pour sélectionner une stratégie de traduction jusqu'à l'exécution. La stratégie de traduction utilisée dans
StringConcatFactory
est similaire àLambdaMetafactory
celle introduite dans la version java précédente. En outre, l'un des objectifs du PEC mentionné dans la question est d'étendre ces stratégies davantage.Spécification des entrées du pool de constantes : - Ce sont les arguments statiques supplémentaires à l'
invokedynamic
instruction autres que (1)MethodHandles.Lookup
objet qui est une fabrique pour créer des descripteurs de méthode dans le contexte de l'invokedynamic
instruction, (2) unString
objet, le nom de la méthode mentionné dans l'appel dynamique site et (3) l'MethodType
objet, la signature de type résolue du site d'appel dynamique.Il y a déjà des liens lors de la liaison du code. Au moment de l'exécution, la méthode d'amorçage s'exécute et les liens dans le code réel effectuant la concaténation. Il réécrit l'
invokedynamic
appel avec uninvokestatic
appel approprié . Cela charge la chaîne constante à partir du pool de constantes, les arguments statiques de la méthode bootstrap sont exploités pour transmettre ces constantes et d'autres directement à l'appel de la méthode bootstrap.Utilisation de l'instruction invokedynamic : - Ceci offre les facilités pour une liaison paresseuse, en fournissant les moyens d'amorcer la cible d'appel une fois, pendant l'appel initial. L'idée concrète d'optimisation ici est de remplacer toute la
StringBuilder.append
danse par un simpleinvokedynamic
appel àjava.lang.invoke.StringConcatFactory
, qui acceptera les valeurs dans le besoin de concaténation.La proposition Indify String Concatenation indique avec un exemple l'analyse comparative de l'application avec Java9 où une méthode similaire à celle partagée par @TJ Crowder est compilée et la différence du bytecode est assez visible entre les différentes implémentations.
la source
Je vais ajouter un peu de détails ici. La principale partie à obtenir est que la façon dont la concaténation de chaînes est effectuée est une décision d'exécution, et non plus une décision de compilation . Ainsi, cela peut changer, ce qui signifie que vous avez compilé votre code une fois contre java-9 et qu'il peut changer l'implémentation sous-jacente comme bon lui semble, sans avoir besoin de recompiler.
Et le deuxième point est qu'en ce moment il y a
6 possible strategies for concatenation of String
:Vous pouvez choisir l' un d'eux via un paramètre:
-Djava.lang.invoke.stringConcat
. Notez queStringBuilder
c'est toujours une option.la source