我试图测量instance of
是否真的很快。这是一个非常简单的基准:
public Object a = 2;
@Benchmark
@Warmup(iterations = 5, timeUnit = TimeUnit.NANOSECONDS)
@Measurement(iterations = 5, timeUnit = TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public boolean test() {
return a instanceof Double;
}
我跑了这个板凳
Benchmark Mode Cnt Score Error Units
MyBenchmark.test avgt 5 3.105 ± 0.086 ns/op
基准测试的组件输出太长,省略。
我还写了一个简单的java程序
private static Object i = 123;
public static boolean insOf(){
return i instanceof Double;
}
public static void main(String[] args) throws IOException {
for (int i = 0; i < 100000000; i++)
if(insOf())
System.out.print("");
}
编译的insOf
方法的程序集输出如下:
0x00007fd761114b60: mov %eax,0xfffffffffffec000(%rsp)
0x00007fd761114b67: push %rbp
0x00007fd761114b68: sub $0x10,%rsp ;*synchronization entry
; - com.get.intent.App::insOf@-1 (line 24)
0x00007fd761114b6c: movabs $0xd6f788e0,%r10 ; {oop(a 'java/lang/Class' = 'com/get/intent/App')}
0x00007fd761114b76: mov 0x68(%r10),%r11d ;*getstatic i
; - com.get.intent.App::insOf@0 (line 24)
0x00007fd761114b7a: mov 0x8(%r11),%r10d ; implicit exception: dispatches to 0x00007fd761114b9c
0x00007fd761114b7e: cmp $0x20002192,%r10d ; {metadata('java/lang/Double')}
0x00007fd761114b85: jne 0x7fd761114b98 <-------- HERE!!!
0x00007fd761114b87: mov $0x1,%eax
0x00007fd761114b8c: add $0x10,%rsp
0x00007fd761114b90: pop %rbp
0x00007fd761114b91: test %eax,0x16774469(%rip) ; {poll_return}
0x00007fd761114b97: retq
0x00007fd761114b98: xor %eax,%eax
0x00007fd761114b9a: jmp 0x7fd761114b8c <------- HERE!!!
0x00007fd761114b9c: mov $0xfffffff4,%esi
0x00007fd761114ba1: nop
0x00007fd761114ba3: callq 0x7fd7610051a0 ; OopMap{off=72}
;*instanceof
; - com.get.intent.App::insOf@3 (line 24)
; {runtime_call}
0x00007fd761114ba8: callq 0x7fd776591a20 ;*instanceof
; - com.get.intent.App::insOf@3 (line 24)
; {runtime_call}
省略了大量hlt
条指令。
从我所看到的,实例是大约有十个具有两次跳转的汇编指令(jne
,jmp
)。跳跃有点令人困惑。我们为什么需要它们?
问题: Java instance of
真的这么快吗?
答案 0 :(得分:2)
嗯,你正在进行反汇编,所以你可能需要重建那些跳转所代表的函数。使用源代码可用且有调试符号的JVM可能是个好主意。
基于instanceof
的语义,我发出这些跳转所做的是为超类递归执行相同的测试(因为基本上instanceof
可以用函数伪代码写成{ {1}}
答案 1 :(得分:1)
是的,对于大多数情况来说这是快速的,包括像你这样的琐碎案例。它首先乐观地检查类型的确切命中(在你的情况下为Double
),然后回退到悲观地调用运行时的慢分支,因为可能需要遍历类层次结构。但是,在Double
的情况下,编译器知道系统中不存在Double
的子类,因此慢速分支通常是“假的”。
mov 0x8(%r11),%r10d ; read the klass ptr
cmp $0x20002192,%r10d ; klass for 'java/lang/Double'
jne NOT_EQUAL ; not equal? slow branch
mov $0x1,%eax ; return value = "true"
RETURN:
add $0x10,%rsp ; epilog
pop %rbp
test %eax,0x16774469(%rip)
retq
NOT_EQUAL:
xor %eax,%eax ; return value = "false"
jmp RETURN