【发布时间】:2013-03-25 17:50:46
【问题描述】:
我写了一个小基准测试java.lang.invoke.MethodHandle、java.lang.reflect.Method 和直接调用方法的性能。
我读到MethodHandle.invoke() 的性能几乎与直接调用相同。但我的测试结果显示另一个:MethodHandle 调用比反射慢大约三倍。我的问题是什么?这可能是一些 JIT 优化的结果吗?
public class Main {
public static final int COUNT = 100000000;
static TestInstance test = new TestInstance();
static void testInvokeDynamic() throws NoSuchMethodException, IllegalAccessException {
int [] ar = new int[COUNT];
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(int.class);
MethodHandle handle = lookup.findStatic(TestInstance.class, "publicStaticMethod", mt) ;
try {
long start = System.currentTimeMillis();
for (int i=0; i<COUNT; i++) {
ar[i] = (int)handle.invokeExact();
}
long stop = System.currentTimeMillis();
System.out.println(ar);
System.out.println("InvokeDynamic time: " + (stop - start));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static void testDirect() {
int [] ar = new int[COUNT];
try {
long start = System.currentTimeMillis();
for (int i=0; i<COUNT; i++) {
ar[i] = TestInstance.publicStaticMethod();
}
long stop = System.currentTimeMillis();
System.out.println(ar);
System.out.println("Direct call time: " + (stop - start));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static void testReflection() throws NoSuchMethodException {
int [] ar = new int[COUNT];
Method method = test.getClass().getMethod("publicStaticMethod");
try {
long start = System.currentTimeMillis();
for (int i=0; i<COUNT; i++) {
ar[i] = (int)method.invoke(test);
}
long stop = System.currentTimeMillis();
System.out.println(ar);
System.out.println("Reflection time: " + (stop - start));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static void testReflectionAccessible() throws NoSuchMethodException {
int [] ar = new int[COUNT];
Method method = test.getClass().getMethod("publicStaticMethod");
method.setAccessible(true);
try {
long start = System.currentTimeMillis();
for (int i=0; i<COUNT; i++) {
ar[i] = (int)method.invoke(test);
}
long stop = System.currentTimeMillis();
System.out.println(ar);
System.out.println("Reflection accessible time: " + (stop - start));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
public static void main(String ... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InterruptedException {
Thread.sleep(5000);
Main.testDirect();
Main.testInvokeDynamic();
Main.testReflection();
Main.testReflectionAccessible();
System.out.println("\n___\n");
System.gc();
System.gc();
Main.testDirect();
Main.testInvokeDynamic();
Main.testReflection();
Main.testReflectionAccessible();
}
}
环境: java 版本 "1.7.0_11" Java(TM) SE Runtime Environment (build 1.7.0_11-b21) Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04,混合模式)操作系统 - Windows 7 64
【问题讨论】:
-
首先确保您知道如何编写基准,请参阅:ibm.com/developerworks/java/library/j-jtp02225/index.html
-
@NathanHughes 他的基准有什么问题?
-
@Andremoniy:最明显的问题是 jvm 没有预热。
-
@Andremoniy:我不知道他的问题是什么,但结果令人怀疑。希望有人会为此提出一个有趣的答案,+1 的问题。
-
我最近做了一个similar benchmark。服务器和客户端 VM 之间的选择,以及方法句柄是否来自静态 final 字段都对性能有很大影响。
标签: java performance methodhandle