jvm 如何关闭字符串串联优化

baubqpgj  于 2022-11-23  发布在  其他
关注(0)|答案(2)|浏览(139)

在Java 9中,Oracle改进了字符串连接。现在"" + someBoolean变成了invokedynamicStringConcatFabric.makeConcat作为引导方法。该结构在运行时生成连接字符串的类。我想禁用此行为,并回退到普通的旧字符串构建器。
所以我想javac有我想要的标志。但是我找不到它。

rslzwgfq

rslzwgfq1#

字符串串联功能有两个部分。
1.在运行时
在Java 9+中,在运行时,字符串连接是由StringConcatFactory类(javadoc)控制的,这是因为javac在需要字符串连接的地方生成invokedynamic字节码到StringConcatFactory::makeConcat
StringConcatFactoryStrategy枚举(源代码)的形式定义了几种运行时连接策略。
您可以通过设置-Djava.lang.invoke.stringConcat从命令行更改缺省策略
要在运行时获得Java-8行为,需要将其设置为BC_SB,即“Bytecode,StringBuilder”
以下是其他值(为了完整起见):

/**
 * 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

*编译时

正如Kayaman正确指出的,StringConcatFactory只在运行时影响程序。无论字符串连接在哪里,字节码仍然包含invokedynamicStringConcatFactory。有几种方法可以取回对StringBuilder的调用:

  • 禁用此行为最直接的方法是将--release=8标志传递给javac,以强制生成与Java-8兼容的代码。
  • 一个更有针对性的选项是通过传递-XDstringConcat=inline来专门控制串联。

让我们以这段代码为例:

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

如果我们编译它而不使用任何标志,我们将得到:

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
}

注意invokedynamicmakeConcatWithConstants
然而,如果我们运行javac -XDstringConcat=inline Print.java,我们将得到:

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
}

这里的String连接是使用StringBuilder完成的,就像在Java 8中一样。

jei2mxaa

jei2mxaa2#

从Java 15开始,StringConcatFactory除了MH_INLINE_SIZED_EXACT之外没有提供其他的连接策略。请参阅邮件列表中的this threadthis bug以了解详细信息。
正如Malt在his answer中指出的,现在只有在编译时禁用invokedynamic才能回到StringBuilder。为此,将-XDstringConcat=inline标志传递给编译器。更多细节请参见上面引用的Malt的答案。
如果使用Maven Central中的JAR文件,you will need to recompile them yourself .

相关问题