Como está escrito en JEP 280: Indique la concatenación de cadenas :
Cambie la
String
secuencia de código de bytes de concatenación estática generada porjavac
para usarinvokedynamic
llamadas a las funciones de la biblioteca JDK. Esto permitirá futuras optimizaciones deString
concatenación sin requerir más cambios en el código de bytes emitido porjavac
.
Aquí quiero entender cuál es el uso de las invokedynamic
llamadas y en qué se diferencia la concatenación de códigos de bytes invokedynamic
.
java
string
string-concatenation
java-9
invokedynamic
Mohit Tyagi
fuente
fuente
Respuestas:
La forma "antigua" genera un montón de
StringBuilder
operaciones orientadas. Considere este programa:Si compilamos eso con JDK 8 o anterior y luego usamos
javap -c Example
para ver el código de bytes, vemos algo como esto:Como puede ver, crea
StringBuilder
y usaappend
. Esto es bastante ineficiente ya que la capacidad predeterminada del búfer incorporadoStringBuilder
es de solo 16 caracteres, y el compilador no tiene forma de saber que debe asignar más por adelantado, por lo que termina teniendo que reasignar. También es un montón de llamadas a métodos. (Sin embargo, tenga en cuenta que la JVM a veces puede detectar y reescribir estos patrones de llamadas para hacerlos más eficientes).Veamos lo que genera Java 9:
Oh Dios, pero eso es más corto. :-) Hace una sola llamada a
makeConcatWithConstants
fromStringConcatFactory
, que dice esto en su Javadoc:fuente
+=
en su bucle for. Les dije que depende, pero no olvidemos que podrían encontrar una mejor manera de encadenar concat en algún momento en el futuro. La línea clave es realmente la penúltima línea:So by being smart, you have caused a performance hit when Java got smarter than you.
invokedynamic
permite elegir diferentes estrategias de concatenación en tiempo de ejecución y enlazarlas en la primera invocación, sin la sobrecarga de una llamada de método y una tabla de despacho en cada invocación; más en el artículo de nicolai aquí y en la JEP .Object
, pero luego tendrías que encasillar todos los primitivos ... (que Nicolai cubre en su excelente artículo, por cierto)String.concat(String)
método ya existente cuya implementación está creando la matriz de la cadena resultante en el lugar. La ventaja se vuelve discutible cuando tenemos que invocartoString()
objetos arbitrarios. Del mismo modo, al llamar a un método que acepta una matriz, la persona que llama tiene que crear y completar la matriz, lo que reduce el beneficio general. Pero ahora, es irrelevante, ya que la nueva solución es básicamente lo que estaba considerando, excepto que no tiene una sobrecarga de boxeo, no necesita creación de matrices y el backend puede generar controladores optimizados para escenarios particulares.Antes de entrar en los detalles de la
invokedynamic
implementación utilizada para la optimización de la concatenación de cadenas, en mi opinión, uno debe obtener algunos antecedentes sobre ¿Qué es invokedynamic y cómo lo uso?Probablemente trataría de explicarle estos cambios con los cambios que se trajeron para la implementación de la optimización de la concatenación de cadenas.
Definición del método Bootstrap : - Con Java9, los métodos bootstrap para
invokedynamic
sitios de llamadas, para admitir la concatenación de cadenas principalmentemakeConcat
ymakeConcatWithConstants
se introdujeron con laStringConcatFactory
implementación.El uso de invokedynamic proporciona una alternativa para seleccionar una estrategia de traducción hasta el tiempo de ejecución. La estrategia de traducción utilizada en
StringConcatFactory
es similar a laLambdaMetafactory
introducida en la versión anterior de Java. Además, uno de los objetivos de la JEP mencionado en la pregunta es ampliar aún más estas estrategias.Especificar entradas de grupo constante : - Estos son los argumentos estáticos adicionales a la
invokedynamic
instrucción que no sean (1)MethodHandles.Lookup
objeto que es una fábrica para crear identificadores de métodos en el contexto de lainvokedynamic
instrucción, (2) unString
objeto, el nombre del método mencionado en la llamada dinámica sitio y (3) elMethodType
objeto, la firma de tipo resuelto del sitio de llamada dinámica.Ya están vinculados durante la vinculación del código. En tiempo de ejecución, el método bootstrap se ejecuta y enlaza en el código real haciendo la concatenación. Reescribe la
invokedynamic
llamada con unainvokestatic
llamada apropiada . Esto carga la cadena constante del grupo constante, los argumentos estáticos del método bootstrap se aprovechan para pasar estas y otras constantes directamente a la llamada al método bootstrap.Uso de la instrucción dinámica invocada : - Esto ofrece las facilidades para un enlace perezoso, proporcionando los medios para arrancar el destino de la llamada una vez, durante la invocación inicial. La idea concreta para la optimización aquí es reemplazar todo el
StringBuilder.append
baile con una simpleinvokedynamic
llamada ajava.lang.invoke.StringConcatFactory
, que aceptará los valores en la necesidad de concatenación.La propuesta de Indify String Concatenation establece con un ejemplo la evaluación comparativa de la aplicación con Java9 donde un método similar al compartido por @TJ Crowder y la diferencia en el es bastante visible entre las diferentes implementaciones.
fuente
Agregaré algunos detalles aquí. La parte principal es que la forma en que se realiza la concatenación de cadenas es una decisión en tiempo de ejecución, ya no en tiempo de compilación . Por lo tanto, puede cambiar, lo que significa que ha compilado su código una vez contra java-9 y puede cambiar la implementación subyacente como le plazca, sin la necesidad de volver a compilar.
Y el segundo punto es que de momento existen
6 possible strategies for concatenation of String
:Usted puede elegir cualquiera de ellos a través de un parámetro:
-Djava.lang.invoke.stringConcat
. Tenga en cuenta queStringBuilder
sigue siendo una opción.fuente