Java String =””与新的String(“”)性能变化

Java String = “” vs. new String(“”) performance change

我已经完成了与本篇文章相同的测试:
新的String()与文字字符串性能

意思是我想测试哪个具有更好的性能。正如我预期的那样,按字面值赋值的速度更快。我不知道为什么,但是我用更多的赋值进行了测试,但我注意到了一些奇怪的事情:当我让程序执行循环超过10.000倍的循环时,按字面值的赋值相对而言并没有比小于10.000赋值时要快得多。 。并且重复1.000.000甚至比创建新对象还要慢。

这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
double tx = System.nanoTime();
for (int i = 0; i<1; i++){
    String s ="test";
}
double ty = System.nanoTime();

double ta = System.nanoTime();
for (int i = 0; i<1; i++){
    String s = new String("test");
}
double tb = System.nanoTime();

System.out.println((ty-tx));
System.out.println((tb-ta));

我让它像上面写的那样运行。我只是在学习Java,我的老板要求我进行测试,当我提交测试结果后,他要求我找到答案,为什么会这样。我无法在Google或stackoverflow上找到任何内容,因此希望有人可以在这里为我提供帮助。

1
2
3
4
5
6
7
factor at         1 repetition   3,811565221
factor at        10 repetitions  4,393570401
factor at       100 repetitions  5,234779103
factor at     1,000 repetitions  7,909884116
factor at    10,000 repetitions  9,395538811
factor at   100,000 repetitions  2,355514697
factor at 1,000,000 repetitions  0,734826755

谢谢!


首先,您必须了解很多有关HotSpot的内部信息,尤其是首先对您的代码进行解释,然后在某个时候编译为本机代码的事实。

基于对代码进行静态和动态分析的结果,编译时会进行很多优化。

具体来说,在您的代码中,

1
String s ="test";

是明确的禁止操作。对于此行,编译器将不会发出任何代码。剩下的只是循环本身,如果HotSpot证明它没有可观察到的外部影响,则可以消除整个循环。

第二,甚至是代码

1
String s = new String("test");

可能会产生与上述几乎相同的结果,因为很容易证明您的new String是无法从创建它的方法中逃脱的实例。

对于您的代码,测量结果混合了解释后的字节码的性能,编译代码并通过堆栈替换替换代码所花费的延迟,然后是本机代码的性能。

基本上,您所进行的测量是测量除您要测量的效果以外的所有内容。

为使参数更扎实,我用jmh

重复了测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 3, time = 1)
@Threads(1)
@Fork(2)
public class Strings
{
  static final int ITERS = 1_000;
  @GenerateMicroBenchmark
  public void literal() {
    for (int i = 0; i < ITERS; i++) { String s ="test"; }
  }

  @GenerateMicroBenchmark
  public void newString() {
    for (int i = 0; i < ITERS; i++) { String s = new String("test"); }
  }
}

这些是结果:

1
2
3
Benchmark     Mode   Samples         Mean   Mean error    Units
literal       avgt         6        0.625        0.023    ns/op
newString     avgt         6       43.778        3.283    ns/op

您可以看到,在使用字符串文字的情况下,整个方法体都被消除了,而使用new String时,循环仍然存在,但其中没有任何内容,因为每次循环迭代的时间仅为0.04纳秒。绝对没有分配String实例。