par*_*ana 2 java string performance
我认为String.indexOf(char)比String.indexOf(String)使用单个字符和单个字符串(例如,'x'和"x")快一点
为了确保我的猜测,我编写了简单的测试代码,如下所示.
public static void main(String[] args) {
IndexOfTest test = new IndexOfTest(Integer.parseInt(args[0]));
test.run();
}
public IndexOfTest(int loop) {
this.loop = loop;
}
public void run() {
long start, end;
start = System.currentTimeMillis();
for(int i = 0 ; i < loop ; i++) {
alphabet.indexOf("x");
}
end = System.currentTimeMillis();
System.out.println("indexOf(String) : " + (end - start) + "ms");
start = System.currentTimeMillis();
for(int i = 0 ; i < loop ; i++) {
alphabet.indexOf('x');
}
end = System.currentTimeMillis();
System.out.println("indexOf(char) : " + (end - start) + "ms");
}
Run Code Online (Sandbox Code Playgroud)
alphabet是具有"abcd ... xyzABCD ... XYZ"的字符串变量.
从这段代码中,我得到了这样的结果表......
loop 10^3 10^4 10^5 10^6 10^7
String 1 7 8 9 9
char 1 2 5 10 64
Run Code Online (Sandbox Code Playgroud)
String.indexOf(String)看起来像收敛到9ms,但是String.indexOf(char)呈指数增长.
我很困惑.在这种情况下是否有使用String的优化?或者我如何弄清楚这个结果?
我用以下两种基准方法运行jmh.每个方法都调用一个indexOf方法.
@State(Scope.Thread)
public class MyBenchmark {
private String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
@Benchmark
public void indexOfString() {
alphabet.indexOf("x");
}
@Benchmark
public void indexOfChar() {
alphabet.indexOf('x');
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
Benchmark Mode Cnt Score Error Units
MyBenchmark.indexOfChar thrpt 30 142106399.525 ± 51360.808 ops/s
MyBenchmark.indexOfString thrpt 30 2178872840.575 ± 864573.421 ops/s
Run Code Online (Sandbox Code Playgroud)
这个结果也表明indexOf(String)更快..
我认为是时候考虑隐藏优化了
任何的想法?
Tag*_*eev 10
您的JMH测试不正确,因为您没有使用结果,因此indexOfJIT编译器可以(或者可以不)删除该调用.在你的情况下,似乎JIT编译器确定indexOf(String)没有副作用并且完全删除了这个调用,但是没有做同样的事情indexOf(char).总是消耗结果(最简单的方法是从基准测试返回).这是我的版本:
import java.util.*;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(3)
public class IndexOfTest {
private String str;
private char c;
private String s;
@Setup
public void setup() {
str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
c = 'z';
s = "z";
}
@Benchmark
public int indexOfChar() {
return str.indexOf('z');
}
@Benchmark
public int indexOfString() {
return str.indexOf("z");
}
@Benchmark
public int indexOfCharIndirect() {
return str.indexOf(c);
}
@Benchmark
public int indexOfStringIndirect() {
return str.indexOf(s);
}
}
Run Code Online (Sandbox Code Playgroud)
我测试了相同的东西,但添加了两个间接测试:当搜索char或从字段加载String时,因此在JIT编译期间其确切值是未知的.结果如下(Intel x64):
# JMH 1.11.2 (released 27 days ago)
# VM version: JDK 1.8.0_45, VM 25.45-b02
Benchmark Mode Cnt Score Error Units
IndexOfTest.indexOfChar avgt 30 25,364 ± 0,424 ns/op
IndexOfTest.indexOfCharIndirect avgt 30 25,287 ± 0,210 ns/op
IndexOfTest.indexOfString avgt 30 24,370 ± 0,100 ns/op
IndexOfTest.indexOfStringIndirect avgt 30 27,198 ± 0,048 ns/op
Run Code Online (Sandbox Code Playgroud)
如您所见,indexOfChar无论是直接访问还是间接访问,都以相同的方式执行.该indexOfString是直接访问间接稍快一些,但略慢.那是因为它indexOf(String)是一个JVM内在的:它的Java代码实际上被JIT编译器替换为高效的内联实现.对于在JIT编译时已知的常量字符串,可以生成更高效的代码.
一般来说,至少对于这样的短字符串没有太大的区别.因此,您可以使用这些方法中的任何一种进行单符号匹配.