反射获取的方法的执行时间是否更长?
Does the execution of a method fetched by Reflection take longer?
众所周知,可以使用 Reflection
获取方法并通过返回的 Method
实例调用它。
但是我的问题是;一旦它被 Reflection
获取并且我一遍又一遍地调用 Method
该方法的性能是否会比调用方法的正常方式慢?
例如:
import java.lang.reflect.Method;
public class ReflectionTest {
private static Method test;
public ReflectionTest() throws Exception {
test = this.getClass().getMethod("testMethod", null);
}
public void testMethod() {
//execute code here
}
public static void main(String[] args) throws Exception {
ReflectionTest rt = new ReflectionTest();
for (int i = 0; i < 1000; i++) {
rt.test.invoke(null, null);
}
for (int i = 0; i < 1000; i++) {
rt.testMethod();
}
}
}
我问这个是因为我正在制作一个事件系统,在注册侦听器时它会扫描注释。这些方法被放入映射中,然后在每次发生所需参数类型的事件时执行它们。我不知道这是否足够高效,例如游戏。
使用不带反射的方法大约快一个数量级。我测试了一下
public static void main(String[] args) throws Exception {
ReflectionTest rt = new ReflectionTest();
// Warm up
for (int i = 0; i < 100; i++) {
test.invoke(rt, null);
}
for (int i = 0; i < 100; i++) {
rt.testMethod();
}
long start = System.nanoTime();
for (int i = 0; i < 10000; i++) {
test.invoke(rt, null);
}
long end = Math.abs((start - System.nanoTime()) / 1000);
start = System.nanoTime();
for (int i = 0; i < 10000; i++) {
rt.testMethod();
}
long end2 = Math.abs((start - System.nanoTime()) / 1000);
System.out.printf("%d %d%n", end, end2);
}
我还将 test
移动到 static
字段,这样它就可以编译并且 运行
private static Method test;
static {
try {
test = ReflectionTest.class.getMethod("testMethod");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
我得到与
相当一致的差异(或一致的输出)
4526 606
这表明 10000
调用反射比直接调用慢 ~7 倍。
@Elliot Frisch 的回答提供了确凿的1 证据表明使用 Method.invoke()
速度较慢。
无论如何你都会预料到这一点,因为反射版本需要额外的工作;例如
- 包含可变参数的数组的创建和初始化,
- 检查数组的长度,并且
- 将数组中的参数从
Object
转换为相应的参数类型。
在某些情况下,JIT 可能会对此进行优化...
1 - 好吧……没有定论。基准测试有问题,因为它没有适当注意处理可能的 JVM 预热异常。
众所周知,可以使用 Reflection
获取方法并通过返回的 Method
实例调用它。
但是我的问题是;一旦它被 Reflection
获取并且我一遍又一遍地调用 Method
该方法的性能是否会比调用方法的正常方式慢?
例如:
import java.lang.reflect.Method;
public class ReflectionTest {
private static Method test;
public ReflectionTest() throws Exception {
test = this.getClass().getMethod("testMethod", null);
}
public void testMethod() {
//execute code here
}
public static void main(String[] args) throws Exception {
ReflectionTest rt = new ReflectionTest();
for (int i = 0; i < 1000; i++) {
rt.test.invoke(null, null);
}
for (int i = 0; i < 1000; i++) {
rt.testMethod();
}
}
}
我问这个是因为我正在制作一个事件系统,在注册侦听器时它会扫描注释。这些方法被放入映射中,然后在每次发生所需参数类型的事件时执行它们。我不知道这是否足够高效,例如游戏。
使用不带反射的方法大约快一个数量级。我测试了一下
public static void main(String[] args) throws Exception {
ReflectionTest rt = new ReflectionTest();
// Warm up
for (int i = 0; i < 100; i++) {
test.invoke(rt, null);
}
for (int i = 0; i < 100; i++) {
rt.testMethod();
}
long start = System.nanoTime();
for (int i = 0; i < 10000; i++) {
test.invoke(rt, null);
}
long end = Math.abs((start - System.nanoTime()) / 1000);
start = System.nanoTime();
for (int i = 0; i < 10000; i++) {
rt.testMethod();
}
long end2 = Math.abs((start - System.nanoTime()) / 1000);
System.out.printf("%d %d%n", end, end2);
}
我还将 test
移动到 static
字段,这样它就可以编译并且 运行
private static Method test;
static {
try {
test = ReflectionTest.class.getMethod("testMethod");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
我得到与
相当一致的差异(或一致的输出)4526 606
这表明 10000
调用反射比直接调用慢 ~7 倍。
@Elliot Frisch 的回答提供了确凿的1 证据表明使用 Method.invoke()
速度较慢。
无论如何你都会预料到这一点,因为反射版本需要额外的工作;例如
- 包含可变参数的数组的创建和初始化,
- 检查数组的长度,并且
- 将数组中的参数从
Object
转换为相应的参数类型。
在某些情况下,JIT 可能会对此进行优化...
1 - 好吧……没有定论。基准测试有问题,因为它没有适当注意处理可能的 JVM 预热异常。