为什么 Java 字符串比较在 Java 15 和 Java 11 中表现不同?
Why does a Java string comparison behave different in Java 15 and Java 11?
请考虑以下内容class:
class Eq {
public static void main(String[] args) {
System.out.println("" == ".".substring(1));
}
}
该示例应该表明内存中可能存在空字符串的多个副本。我仍然有一个旧的 OpenJDK 11,其中程序按预期输出 false
。在 OpenJDK 15 下,程序输出 true
。 class 文件生成的字节码看起来很相似(尽管它们的寄存器值不同):
Java 11:
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #13 // String
5: ldc #15 // String .
7: iconst_1
8: invokevirtual #17 // Method java/lang/String.substring:(I)Ljava/lang/String;
11: if_acmpne 18
14: iconst_1
15: goto 19
18: iconst_0
19: invokevirtual #23 // Method java/io/PrintStream.println:(Z)V
22: return
Java 15:
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String
5: ldc #4 // String .
7: iconst_1
8: invokevirtual #5 // Method java/lang/String.substring:(I)Ljava/lang/String;
11: if_acmpne 18
14: iconst_1
15: goto 19
18: iconst_0
19: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
22: return
我试图通过读取“.”来排除静态编译器优化。来自 stdin 但这不会改变结果。我试图通过 -Djava.compiler=NONE
禁用 JIT,并尝试通过 -XX:StringTableSize=100000
调整字符串 table 的大小。我现在有以下问题:
- 有人可以重现这个问题吗(即我做对了吗?如果有帮助,我可以提供 class 文件)
- 如何找出不同行为的确切原因?
- (在您看来)不同行为的根源是什么?
我认为只是解决如何找到未回答问题的行为的原因的策略也可能很有趣。
中有提到
已根据 JDK-8240094 的要求更改:
JDK-8240094 : Optimize empty substring handling
String.substring
return ""
in some cases, but could be improved to do so in all cases when the substring length is zero.
相关:
JDK-8240225 : Optimize empty substring handling
Optimize String.substring
and related operations like stripLeading
, stripTrailing
to avoid redundantly creating a new empty String.
子任务:
JDK-8251556 : Release Note: Optimized Empty Substring Handling
The implementation of String.substring
and related methods stripLeading
and stripTrailing
have changed in this release to avoid redundantly creating a new empty String. This may impact code that depends on unspecified behaviour and the identity of empty sub-strings.
请考虑以下内容class:
class Eq {
public static void main(String[] args) {
System.out.println("" == ".".substring(1));
}
}
该示例应该表明内存中可能存在空字符串的多个副本。我仍然有一个旧的 OpenJDK 11,其中程序按预期输出 false
。在 OpenJDK 15 下,程序输出 true
。 class 文件生成的字节码看起来很相似(尽管它们的寄存器值不同):
Java 11:
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #13 // String
5: ldc #15 // String .
7: iconst_1
8: invokevirtual #17 // Method java/lang/String.substring:(I)Ljava/lang/String;
11: if_acmpne 18
14: iconst_1
15: goto 19
18: iconst_0
19: invokevirtual #23 // Method java/io/PrintStream.println:(Z)V
22: return
Java 15:
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String
5: ldc #4 // String .
7: iconst_1
8: invokevirtual #5 // Method java/lang/String.substring:(I)Ljava/lang/String;
11: if_acmpne 18
14: iconst_1
15: goto 19
18: iconst_0
19: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
22: return
我试图通过读取“.”来排除静态编译器优化。来自 stdin 但这不会改变结果。我试图通过 -Djava.compiler=NONE
禁用 JIT,并尝试通过 -XX:StringTableSize=100000
调整字符串 table 的大小。我现在有以下问题:
- 有人可以重现这个问题吗(即我做对了吗?如果有帮助,我可以提供 class 文件)
- 如何找出不同行为的确切原因?
- (在您看来)不同行为的根源是什么?
我认为只是解决如何找到未回答问题的行为的原因的策略也可能很有趣。
已根据 JDK-8240094 的要求更改:
JDK-8240094 : Optimize empty substring handling
String.substring
return""
in some cases, but could be improved to do so in all cases when the substring length is zero.
相关:
JDK-8240225 : Optimize empty substring handling
Optimize
String.substring
and related operations likestripLeading
,stripTrailing
to avoid redundantly creating a new empty String.
子任务:
JDK-8251556 : Release Note: Optimized Empty Substring Handling
The implementation of
String.substring
and related methodsstripLeading
andstripTrailing
have changed in this release to avoid redundantly creating a new empty String. This may impact code that depends on unspecified behaviour and the identity of empty sub-strings.