问题描述
我写了一个基准测试来测试 java.lang.invoke.MethodHandle
, java.lang.reflect.Method $ c的性能$ c>和方法的直接调用。
I wrote a little benchmark that tests performance of java.lang.invoke.MethodHandle
, java.lang.reflect.Method
and direct calls of methods.
我读到 MethodHandle.invoke()
表现几乎与直接通话相同。但我的测试结果显示另一个: MethodHandle
调用比反射慢大约三倍。我的问题是什么?可能这是一些JIT优化的结果?
I read that MethodHandle.invoke()
performance almost the same as direct calls. But my test results show another: MethodHandle
invoke about three times slower than reflection. What is my problem? May be this is result of some JIT optimisations?
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_11Java(TM)SE运行时环境(版本1.7.0_11-b21)Java HotSpot(TM)64位服务器VM(版本23.6-b04,混合模式)操作系统 - Windows 7 64
Environment: java version "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, mixed mode) OS - Windows 7 64
推荐答案
看起来@AlekseyShipilev在参考不同的查询时间接回答了这个问题。
在以下链接中
Looks like this was indirectly answered by @AlekseyShipilev in reference to a different query. In the following linkHow can I improve performance of Field.set (perhap using MethodHandles)?
如果您通读,您将看到显示类似结果的其他基准。很可能直接调用可以通过JIT以
的方式简单地优化。根据上面的调查结果,差异是:
MethodHandle.invoke = ~195ns
MethodHandle.invokeExact = ~10ns
直接电话= 1.266ns
If you read through you will see additional benchmarks that show similar findings. It is likely that direct calls can simply be optimized by JIT in ways that According to the findings above, the difference is:MethodHandle.invoke =~195nsMethodHandle.invokeExact =~10nsDirect calls = 1.266ns
所以 - 直接通话仍然会更快,但MH非常快。
对于大多数用例来说,这应该足够了,并且肯定比旧的反射框架更快(顺便说一句 - 根据上面的发现,在java8 vm下反射也明显更快)
So - direct calls will still be faster, but MH is very fast.For most use-cases this should be sufficient and is certainly faster than the old reflection framework (btw - according to the findings above, reflection is also significantly faster under java8 vm)
如果您的系统中这种差异很大,我会建议找到不同的模式,而不是直接反射,这将支持直接调用。
If this difference is significant in your system, i would suggest finding different patterns rather than direct reflection which will support direct calls.
这篇关于MethodHandle性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!