Conforme escrito em JEP 280: Indify String Concatenation :
Altere a
String
sequência de bytecode de concatenação estática gerada porjavac
para usarinvokedynamic
chamadas para funções de biblioteca JDK. Isso permitirá otimizações futuras deString
concatenação sem a necessidade de alterações adicionais no bytecode emitido porjavac
.
Aqui eu quero entender o que é o uso de invokedynamic
chamadas e como a concatenação de bytecode é diferente invokedynamic
?
java
string
string-concatenation
java-9
invokedynamic
Mohit Tyagi
fonte
fonte
Respostas:
O método "antigo" produz um monte de
StringBuilder
operações orientadas. Considere este programa:Se compilarmos isso com JDK 8 ou anterior e, em seguida, usarmos
javap -c Example
para ver o bytecode, veremos algo assim:Como você pode ver, ele cria um
StringBuilder
e usaappend
. Isso é bastante ineficiente, pois a capacidade padrão do buffer embutidoStringBuilder
é de apenas 16 caracteres e não há como o compilador saber alocar mais com antecedência, então ele acaba tendo que realocar. É também um monte de chamadas de método. (Observe que a JVM às vezes pode detectar e reescrever esses padrões de chamadas para torná-los mais eficientes.)Vejamos o que o Java 9 gera:
Oh meu, mas isso é mais curto. :-) Ele faz uma única chamada para
makeConcatWithConstants
fromStringConcatFactory
, que diz isso em seu Javadoc:fonte
+=
no loop for. Eu disse a eles que depende, mas não vamos esquecer que eles podem encontrar uma maneira melhor de concatenar em cadeia em algum momento. A linha principal é realmente a penúltima linha:So by being smart, you have caused a performance hit when Java got smarter than you.
invokedynamic
permite que diferentes estratégias de concatenação sejam escolhidas em tempo de execução e vinculadas na primeira chamada, sem a sobrecarga de uma chamada de método e tabela de despacho em cada chamada; mais no artigo de nicolai aqui e no JEP .Object
, mas então você teria que encaixotar todos os primitivos ... (que Nicolai cobre em seu excelente artigo, aliás.)String.concat(String)
método já existente cuja implementação é criar o array da string resultante no local. A vantagem torna-se discutível quando temos que invocartoString()
objetos arbitrários. Da mesma forma, ao chamar um método que aceita um array, o chamador deve criar e preencher o array, o que reduz o benefício geral. Mas agora, é irrelevante, pois a nova solução é basicamente o que você estava considerando, exceto que não tem sobrecarga de boxing, não precisa de criação de array e o back-end pode gerar manipuladores otimizados para cenários específicos.Antes de entrar nos detalhes da
invokedynamic
implementação usada para otimização da concatenação de String, na minha opinião, é necessário obter algumas informações sobre o que é invokedynamic e como faço para usá-lo?Provavelmente, eu tentaria levá-lo através delas com as mudanças que foram trazidas para a implementação da otimização de concatenação de String.
Definindo o método de bootstrap: - Com Java9, os métodos de bootstrap para
invokedynamic
sites de chamadas, para suportar a concatenação de strings principalmentemakeConcat
emakeConcatWithConstants
foram introduzidos com aStringConcatFactory
implementação.O uso de invokedynamic fornece uma alternativa para selecionar uma estratégia de tradução até o tempo de execução. A estratégia de tradução usada
StringConcatFactory
é semelhante àLambdaMetafactory
introduzida na versão anterior do java. Além disso, um dos objetivos do JEP mencionado na pergunta é estender ainda mais essas estratégias.Especificando Entradas de Pool Constantes : - Estes são os argumentos estáticos adicionais para a
invokedynamic
instrução diferente de (1)MethodHandles.Lookup
objeto que é uma fábrica para criar identificadores de método no contexto dainvokedynamic
instrução, (2) umString
objeto, o nome do método mencionado na chamada dinâmica site e (3) oMethodType
objeto, a assinatura do tipo resolvido do site de chamada dinâmica.Já estão vinculados durante a vinculação do código. No tempo de execução, o método de bootstrap é executado e vinculado ao código real fazendo a concatenação. Ele reconfigura a
invokedynamic
chamada com umainvokestatic
chamada apropriada . Isso carrega a string constante do pool constante, os argumentos estáticos do método bootstrap são aproveitados para passar essas e outras constantes diretamente para a chamada do método bootstrap.Usando a Instrução invokedynamic : - Oferece as facilidades para uma ligação lenta, fornecendo os meios para inicializar o destino da chamada uma vez, durante a invocação inicial. A ideia concreta para otimização aqui é substituir toda a
StringBuilder.append
dança por uma simplesinvokedynamic
chamada parajava.lang.invoke.StringConcatFactory
, que aceitará os valores na necessidade de concatenação.A proposta do Indify String Concatenation afirma com um exemplo o benchmarking do aplicativo com Java9, onde um método semelhante ao compartilhado por @TJ Crowder é compilado e a diferença no bytecode é bastante visível entre as várias implementações.
fonte
Vou adicionar um pouco de detalhes aqui. A parte principal a se entender é que a forma como a concatenação de strings é feita é uma decisão de tempo de execução, não mais uma decisão de tempo de compilação . Portanto, ele pode mudar, o que significa que você compilou seu código uma vez com o java-9 e pode alterar a implementação subjacente da maneira que quiser, sem a necessidade de recompilar.
E o segundo ponto é que no momento existem
6 possible strategies for concatenation of String
:Você pode escolher qualquer um deles através de um parâmetro:
-Djava.lang.invoke.stringConcat
. Observe queStringBuilder
ainda é uma opção.fonte