Cómo desactivar la optimización de la concatenación de cadenas

Yuri Barinov:

En Java 9 Oracle mejoró concatenación de cadenas. Ahora "" + someBooleanse convierte en invokedynamiccon StringConcatFabric.makeConcatcomo método de arranque. Esa tela genera las clases en tiempo de ejecución que concatenan sus cuerdas. Quiero desactivar este comportamiento y vuelve a los constructor de cadena sencilla de edad.
Por lo que se supone que tiene javac bandera que hacer lo que quiera. Pero no puedo encontrarlo.

malta:

Hay dos partes en la función de concatenación de cadenas.

  1. En tiempo de ejecución

    En Java 9+, en tiempo de ejecución, concatenación de cadenas es controlado por la StringConcatFactoryclase ( javadoc ). Eso es porque javacgenera invokedynamiccódigo de bytes a StringConcatFactory::makeConcatdonde se necesite concatenación de cadenas.

    StringConcatFactorydefine varias estrategias para el tiempo de ejecución de concatenación en la forma de un Strategyenum ( código fuente ).

    Se puede cambiar la estrategia por defecto desde la línea de comandos de configuración -Djava.lang.invoke.stringConcat

    Para obtener el comportamiento de Java-8 en tiempo de ejecución, es necesario configurarlo para que BC_SB, acrónimo de "código de bytes, StringBuilder"

    Aquí están los otros valores, para lo completo:

    /**
     * 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
    
  2. En tiempo de compilación

    Como Kayaman señala correctamente, la StringConcatFactoryafecta el programa en tiempo de ejecución solamente. El código de bytes todavía contendrá una invokedynamica StringConcatFactorydonde quiera cadenas se concatenan. Hay varias maneras de volver a las llamadas StringBuilder:

    • El enfoque más directo de desactivar este comportamiento es pasar la --release=8bandera a javac para forzar la generación de Java-8 Código compatibles. Sin embargo, esto no sólo afecta a la concatenación de cadenas.

    • Una opción más específico es el control de concatenación específicamente, mediante el paso -XDstringConcat=inline.

      Tomemos este pedazo de código como un ejemplo:

      public class Print {    
          public static void main(String[] args) {
              String foo = "a";
              String bar = "b";
              System.out.println(foo+bar);
          }
      }
      

      Si se compila sin ningún tipo de banderas, obtendremos:

      public class Print {
        public Print();
          Code:
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
      
        public static void main(java.lang.String[]);
          Code:
             0: ldc           #2                  // String a
             2: astore_1
             3: ldc           #3                  // String b
             5: astore_2
             6: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
             9: aload_1
            10: aload_2
            11: invokedynamic #5,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
            16: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            19: return
      }
      

      Tenga en cuenta el invokedynamica makeConcatWithConstants.

      Sin embargo, si corremos javac -XDstringConcat=inline Print.java, nos pondremos esto:

      public class Print {
        public Print();
          Code:
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
      
        public static void main(java.lang.String[]);
          Code:
             0: ldc           #2                  // String a
             2: astore_1
             3: ldc           #3                  // String b
             5: astore_2
             6: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
             9: new           #5                  // class java/lang/StringBuilder
            12: dup
            13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
            16: aload_1
            17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            20: aload_2
            21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
            27: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            30: return
      }
      

      Aquí la Stringconcatenación se realiza mediante el StringBuilder, al igual que en Java 8.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=330031&siteId=1
Recomendado
Clasificación