Java 字符串 = " " 与新字符串( " " ) 性能变化



我做了与本文相同的测试:new String()与文字字符串性能

这意味着我想测试哪一个在性能上更好。正如我所预料的那样,结果是文字赋值更快。我不知道为什么,但我做了更多的赋值测试,我注意到了一些奇怪的事情:当我让程序循环超过10000次时,文字赋值相对来说没有少于10000次快得多。在1.000.000次重复时,它甚至比创建新对象还要慢。

这是我的代码:

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,我的老板让我做测试,在我给出测试结果后,他让我找到答案,为什么会发生这种情况。我在谷歌或stackoverflow上找不到任何东西,所以我希望有人能在这里帮助我。

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的内部结构,特别是您的代码首先被解释,然后在某个时刻被编译为本机代码。

编译时会根据代码的静态和动态分析结果进行大量优化。

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

String s = "test";

是一个明显的反对。编译器将不为这一行发出任何代码。剩下的只是循环本身,如果HotSpot证明它没有可观察到的外部影响,整个循环可能会被消除。

第二,即使是代码

String s = new String("test");

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

对于您的代码,测量结果会混淆解释的字节码的性能、编译代码并通过On Stack Replacement进行交换所需的延迟,以及本机代码的性能。

基本上,你正在进行的测量是测量所有东西,但你已经开始测量的效果。

为了使论点更加可靠,我用jmh:重复了测试

@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"); }
}
}

结果如下:

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实例。

最新更新