Javac StringBuilder/StringBuffer 优化是什么时候引入的?
When was Javac StringBuilder/StringBuffer optimization introduced?
我知道 Javac 编译器能够使用 StringBuilder
/StringBuffer
转换字符串连接 +
,我很想知道 从哪个版本开始引入了这个变化?
我正在使用这个示例代码:
public class Main {
public static void main(String[] args) {
String a = args[0];
String s = "a";
s = s + a;
s = s + "b";
s = s + "c";
s = s + "d";
s = s + "e";
System.out.println(s);
}
}
到目前为止,我已经尝试使用 javac 1.8.0_121
、javac 1.6.0_20
、javac 1.5.0_22
和 java 1.4.2_19
。
这是我使用 1.4.2_19
中的 javap -c
看到的字节码示例:
6: astore_2
7: new #3; //class StringBuffer
10: dup
11: invokespecial #4; //Method java/lang/StringBuffer."<init>":()V
14: aload_2
15: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
18: aload_1
19: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22: invokevirtual #6; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
所有 4 个版本似乎都在使用 StringBuilder/StringBuffer 优化,所以我很想知道 从哪个 Javac 版本 开始引入此更改?
引用自 language specification from version 1:
An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String
object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer
class (§20.13) or a similar technique to reduce the number of intermediate String
objects that are created by evaluation of an expression.
当时,他们 StringBuffer
而不是 StringBuilder
。
也引自 JDK1.0.2 的StringBuffer
:
This Class is a growable buffer for characters. It is mainly used to create Strings. The compiler uses it to implement the "+" operator.
我查阅了 Java 语言规范,第一版(自 1996 年起)。不容易找到,但是 here it is。连接优化的段落甚至在那里:
An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class (§20.13) or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
规范与 StringBuffer
有关,但 StringBuilder
(当前 JLS 措辞所指)可能被认为性能更好,因为它的方法不是同步的。
然而,这并不意味着应该依赖优化,因为 always 就位。例如,循环中的字符串连接不会得到优化。
JLS已经在一些答案中给出了。我只想指出 StringBuffer (https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html) 自 1.0 以来就存在,而
StringBuilder(https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html) 出现在版本 1.5 中。请参阅相应 javadoc 的 since:
部分。
这没有回答问题,但我只想补充一点,在 jdk-9 中,这个 StringBuilder::append
是 允许的策略之一,但不是默认策略。
private enum Strategy {
/**
* 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
}
它实际上是一个用于字符串连接的 invokedynamic
字节码,因此它的实现现在是 JRE 特定的,而不是编译器的。顺便说一句,默认策略是:MH_INLINE_SIZED_EXACT
我知道 Javac 编译器能够使用 StringBuilder
/StringBuffer
转换字符串连接 +
,我很想知道 从哪个版本开始引入了这个变化?
我正在使用这个示例代码:
public class Main {
public static void main(String[] args) {
String a = args[0];
String s = "a";
s = s + a;
s = s + "b";
s = s + "c";
s = s + "d";
s = s + "e";
System.out.println(s);
}
}
到目前为止,我已经尝试使用 javac 1.8.0_121
、javac 1.6.0_20
、javac 1.5.0_22
和 java 1.4.2_19
。
这是我使用 1.4.2_19
中的 javap -c
看到的字节码示例:
6: astore_2
7: new #3; //class StringBuffer
10: dup
11: invokespecial #4; //Method java/lang/StringBuffer."<init>":()V
14: aload_2
15: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
18: aload_1
19: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22: invokevirtual #6; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
所有 4 个版本似乎都在使用 StringBuilder/StringBuffer 优化,所以我很想知道 从哪个 Javac 版本 开始引入此更改?
引用自 language specification from version 1:
An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate
String
object. To increase the performance of repeated string concatenation, a Java compiler may use theStringBuffer
class (§20.13) or a similar technique to reduce the number of intermediateString
objects that are created by evaluation of an expression.
当时,他们 StringBuffer
而不是 StringBuilder
。
也引自 JDK1.0.2 的StringBuffer
:
This Class is a growable buffer for characters. It is mainly used to create Strings. The compiler uses it to implement the "+" operator.
我查阅了 Java 语言规范,第一版(自 1996 年起)。不容易找到,但是 here it is。连接优化的段落甚至在那里:
An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class (§20.13) or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
规范与 StringBuffer
有关,但 StringBuilder
(当前 JLS 措辞所指)可能被认为性能更好,因为它的方法不是同步的。
然而,这并不意味着应该依赖优化,因为 always 就位。例如,循环中的字符串连接不会得到优化。
JLS已经在一些答案中给出了。我只想指出 StringBuffer (https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html) 自 1.0 以来就存在,而
StringBuilder(https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html) 出现在版本 1.5 中。请参阅相应 javadoc 的 since:
部分。
这没有回答问题,但我只想补充一点,在 jdk-9 中,这个 StringBuilder::append
是 允许的策略之一,但不是默认策略。
private enum Strategy {
/**
* 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
}
它实际上是一个用于字符串连接的 invokedynamic
字节码,因此它的实现现在是 JRE 特定的,而不是编译器的。顺便说一句,默认策略是:MH_INLINE_SIZED_EXACT