字符串池:"Te" +"st"比“测试"更快? [英] String Pool: "Te"+"st" faster than "Test"?
问题描述
我正在尝试一些有关String Pool的性能基准.但是,结果出乎意料.
I am trying some performance benchmark regarding String Pool. However, the outcome is not expected.
我做了3种静态方法
- perform0()方法...每次创建一个新对象
- perform1()方法...字符串文字"Test"
- perform2()方法...字符串常量表达式"Te" +"st"
我的期望是(1.最快-> 3.最快)
My expectation was (1. fastest -> 3. slowest)
- 测试"是由于字符串池
- "Te" +"st"是因为存在字符串池,但是由于+运算符而比1慢一些
- 新的String(..),因为没有字符串池.
但是基准测试表明,"Te" +"st"比"Test"要快一点.
But the benchmark shows that "Te"+"st" is slighty faster than "Test".
new String(): 141677000 ns
"Test" : 1148000 ns
"Te"+"st" : 1059000 ns
new String(): 141253000 ns
"Test" : 1177000 ns
"Te"+"st" : 1089000 ns
new String(): 142307000 ns
"Test" : 1878000 ns
"Te"+"st" : 1082000 ns
new String(): 142127000 ns
"Test" : 1155000 ns
"Te"+"st" : 1078000 ns
...
代码如下:
import java.util.concurrent.TimeUnit;
public class StringPoolPerformance {
public static long perform0() {
long start = System.nanoTime();
for (int i=0; i<1000000; i++) {
String str = new String("Test");
}
return System.nanoTime()-start;
}
public static long perform1() {
long start = System.nanoTime();
for (int i=0; i<1000000; i++) {
String str = "Test";
}
return System.nanoTime()-start;
}
public static long perform2() {
long start = System.nanoTime();
for (int i=0; i<1000000; i++) {
String str = "Te"+"st";
}
return System.nanoTime()-start;
}
public static void main(String[] args) {
long time0=0, time1=0, time2=0;
for (int i=0; i<100; i++) {
// result
time0 += perform0();
time1 += perform1();
time2 += perform2();
}
System.out.println("new String(): " + time0 + " ns");
System.out.println("\"Test\" : " + time1 + " ns");
System.out.println("\"Te\"+\"st\" : " + time2 + " ns");
}
}
有人可以解释为什么"Te" +"st"比"Test"执行得更快吗? JVM在这里进行一些优化吗?谢谢.
Can someone explain why "Te"+"st" performs faster than "Test"? Is JVM doing some optimizations here? Thank you.
推荐答案
"Te" + "st"
是编译器时的常量表达式,因此在运行时的表现与简单地"Test"
一样.任何对性能的影响都将出现在尝试编译时,而不是尝试运行时.
"Te" + "st"
is a compiler-time constant expression, and so will behave at runtime no differently than simply "Test"
. Any performance hit will be when trying to compile it, not when trying to run it.
使用javap -c StringPoolPerformance
拆解已编译的基准测试类可以很容易地证明这一点:
That's easily proven by disassembling your compiled benchmark class using javap -c StringPoolPerformance
:
public static long perform1();
Code:
...
7: ldc #3; //int 1000000
9: if_icmpge 21
12: ldc #5; //String Test
14: astore_3
15: iinc 2, 1
...
public static long perform2();
Code:
...
7: ldc #3; //int 1000000
9: if_icmpge 21
12: ldc #5; //String Test
14: astore_3
15: iinc 2, 1
...
方法的字节码绝对相同!这由 Java指定语言规范,15.18.1 :
The methods' byte code are absolutely identical! This is specified by the Java Language Specification, 15.18.1:
String对象是新创建的(第12.5节),除非该表达式是编译时常量表达式(第15.28节).
The String object is newly created (§12.5) unless the expression is a compile-time constant expression (§15.28).
您遇到的基准差异可能是由于典型的可变性或基准不完美所致.看到以下问题:如何编写正确的micro- Java中的基准测试?
The benchmark difference you experience is probably due to typical variability or because your benchmark isn't perfect. See this question: How do I write a correct micro-benchmark in Java?
您违反了一些值得注意的规则:
Some notable rules you break:
- 您不会丢弃测试内核的热身"迭代的结果.
- 您没有启用GC日志记录(尤其是在总是在创建一个百万个对象的测试之后立即运行
perform1()
的情况下,这一点特别重要.)
这篇关于字符串池:"Te" +"st"比“测试"更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!