static int add(int a, int b){
return a + b;
}
@Test
public void directAdd() throws Throwable {
// 编译 31ms
System.out.println(System.currentTimeMillis());
int r = 0;
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
r += add(i, j);
}
}
System.out.println(r);
System.out.println(System.currentTimeMillis());
}
@Test
public void directAddBoxing() throws Throwable {
// 使用 Integer,引入 boxing unboxing 开销,526ms
System.out.println(System.currentTimeMillis());
int r = 0;
for (Integer i = 0; i < 10000; i++) {
for (Integer j = 0; j < 10000; j++) {
r += add(i, j);
}
}
System.out.println(r);
System.out.println(System.currentTimeMillis());
}
@Test
public void invokeReflectionTest() throws Throwable {
// 反射 1s127ms
Method add = RuntimeOptimization.class.getDeclaredMethod("add", int.class, int.class);
System.out.println(System.currentTimeMillis());
int r = 0;
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
r += (int) add.invoke(null, i, j);
}
}
System.out.println(r);
System.out.println(System.currentTimeMillis());
}
@Test
public void invokeMethodHandlerTest() throws Throwable {
// MethodHandler 210ms
MethodHandle add = MethodHandles.lookup().findStatic(RuntimeOptimization.class, "add", MethodType.methodType(int.class, int.class, int.class));
System.out.println(System.currentTimeMillis());
int r = 0;
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
r += (int) add.invokeExact(i, j);
}
}
System.out.println(r);
System.out.println(System.currentTimeMillis());
}
可见 MethodHandler 比boxing/unboxing的编译版本还要快,显然它在编译时消除了boxing开销,也就是说 invokeExact(Object...) 并不会真的 boxing,Object invokeExtract 也不返回 Object 后再 unboxing 到 int。所以不必纠结为何不提供 add.pushInt(a).pushInt(b).invoke()
这样的结构,编译器已经做了这项优化。
当然,再怎么折腾还是比编译版本慢 10 倍,目前没有更好的办法了。