Java中对象创建的性能度量
我试图比较创建某个类的对象与从Java中对象创建的性能度量,java,performance,jmh,Java,Performance,Jmh,我试图比较创建某个类的对象与从byte[]创建String的性能。以下是我为此编写的基准: public class MyBenchmark { @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void tsts(Blackhole b) { b.consume(new TestClass(i(), str()));
byte[]
创建String
的性能。以下是我为此编写的基准:
public class MyBenchmark {
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void tsts(Blackhole b) {
b.consume(new TestClass(i(), str()));
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void str(Blackhole b) {
b.consume(new String(b()));
}
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public String str(){
return "asdasfa";
}
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public int i(){
return 23;
}
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public byte[] b(){
return new byte[]{49, 66, 43, 65, 78, 123, 96, 54};
}
}
在哪里
private static class TestClass{
private int i;
private String s;
public TestClass(Integer i, String s) {
this.i = i;
this.s = s;
}
}
在我的机器上,我得到了以下结果:
Benchmark Mode Cnt Score Error Units
MyBenchmark.str avgt 20 47.695 ± 1.869 ns/op
MyBenchmark.tsts avgt 20 6.999 ± 0.191 ns/op
这样做正确吗?或者我在基准测试中犯了一些错误,遗漏了一些东西?这是因为JIT知道文本字符串isntance(“asdasfa”)的确切地址。因此,在这种情况下,不需要创建新对象。如果反编译str()方法,您可以清楚地看到它: 该方法由一条指令movabs rax,0x1bc1f1440组成,它将一个地址放入rax寄存器,这就是为什么它更快的原因。其他说明是辅助的
对于另一个方法str(Blackhole b),您将看到更多内容,包括一个已编译的字符串构造函数体,通过方法调用获取默认字符集并解码字节数组。可能JVM优化了
新TestClass()
(类的坏名称,顺便说一句)每次返回相同的单个实例,因此,每次只调用一次i
和str
(更多的坏名称)。说到坏名称,将str
重载为具有相同名称的两个完全不同的方法是另一个例子。@LewBloch这就是我问这个问题的原因。也许JVM做了我没想到的事情。就像总是返回同一个实例一样。现在尝试使用-prof gc
,-prof perfasm
等,这将是一个启发。在信任基准之前,您必须分析基准。
0x000000010dd1a2b0: sub rsp,0x18
0x000000010dd1a2b7: mov QWORD PTR [rsp+0x10],rbp ;
0x000000010dd1a2bc: movabs rax,0x1bc1f1440 ; {oop("asdasfa")}
0x000000010dd1a2c6: add rsp,0x10
0x000000010dd1a2ca: pop rbp
0x000000010dd1a2cb: test DWORD PTR [rip+0xfffffffffe642d2f],eax # 0x000000010c35d000;
0x000000010dd1a2d1: ret