字符串池:"Te" +"st"比“测试"更快? [英] String Pool: "Te"+"st" faster than "Test"?

查看:95
本文介绍了字符串池:"Te" +"st"比“测试"更快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试一些有关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)

  1. 测试"是由于字符串池
  2. "Te" +"st"是因为存在字符串池,但是由于+运算符而比1慢一些
  3. 新的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:

  1. 您不会丢弃测试内核的热身"迭代的结果.
  2. 您没有启用GC日志记录(尤其是在总是在创建一个百万个对象的测试之后立即运行perform1() 的情况下,这一点特别重要.)

这篇关于字符串池:"Te" +"st"比“测试"更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆