我编写了一个测试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位服务器VM(build 23.6-B04,混合模式)OS-Windows 7 64
看起来@AlekseyShipilev在引用另一个查询时间接地回答了这个问题。在下面的链接中,我如何提高field.set(使用MethodHandles的perhap)的性能?
如果通读,您将看到显示类似发现的附加基准。直接调用很可能可以简单地通过JIT优化,根据上面的发现,不同之处在于:
所以--直接通话还是会更快,但MH非常快。对于大多数用例,这应该是足够的,并且肯定比旧的反射框架更快(顺便说一句--根据上面的发现,反射在java8 vm下也要快得多)
如果这种差异在您的系统中很明显,我会建议寻找不同的模式,而不是支持直接调用的直接反射。
编辑: 这就是我得到的:
问题内容: 我正在研究JDK 1.7的新功能,但我无法了解MethodHandle是为什么设计的?我了解静态方法的(直接)调用(以及在这种情况下简单的Core Reflection API的使用)。我也了解(直接)调用虚拟方法(非静态,非最终)(以及使用需要经过Class层次结构的Core Reflection API )。非虚拟方法的调用可以视为前一种的特殊情况。 是的,我知道重载存在问题。如果
我正在尝试在我的Android应用中使用 SOAP 服务。我正在尝试遵循本指南。当我尝试运行我的应用程序时,我收到一个错误: 我使用的是Android N(SDK 25-我不能像错误消息所示那样跳到26),这是Android Studio刚刚创建的一个全新项目。 这是我的项目构建.gradle文件,我没有改变: 这是我的app build.gradle文件: 从日志中可以看出,导致这种情况的确切
我尝试通过methodhandles将方法链接在一起,其中一些方法来自泛型类型。如果函数返回泛型类型,我必须为MethodType指定Object.Class,但我看不到将其转换回泛型类型参数类型的简单方法。在大多数情况下,这没有问题,因为invoke似乎自动转换它们,但我必须创建mhs,它可以用InvokeExact运行。难道没有简单的方法使用MethodHandles进行强制转换吗? 我的测试
Java7引入了MethodHandle类,用于动态执行给定类的方法。据我所知,在JDK的Android端口上没有这样的东西。除了使用标准的反射类之外,是否有任何解决方法可以用来绕过这个问题?
问题内容: 我如何通过获得所有声明的方法?如何获取所有声明的字段? 有什么区别,和 另外,对于使用MethodHandle API for Java devloper的 教程,我将不胜感激。我强调,我是在使用静态类型语言的普通Java上编程的,并且我不是JVM开发人员,尤其是我对整个字节码废话(invokedynamic)不感兴趣。我想弄清楚如何使用此新API代替Java Core API。 编辑