使用反射调用方法与直接调用方法有什么性能差异?
上下文详细信息: 我有一个类,有一些字符串属性,对于某些属性,我必须将值设置为小写或大写(以及与之相关的一些逻辑)。
我有两个选择:
当然使用选项2.我的代码更易读,更易于维护,但问题在于性能。如果性能影响不超过20秒,我会有几百万(大约2-3个)实例,我会选择反射选项。
这里有没有人有这方面的经验?
答案 0 :(得分:3)
很难给出一个固定的数字,因为它取决于你系统的许多方面,所以我写了一个类来检查它。
结果让我感到惊讶,似乎对于我的系统而言,简单地通过反射调用方法与静态调用方法相比,静态调用在非空方法的10,000之间和空方法的1000,000倍之间。
我使用了两者,以防java编译器/ vm优化掉一个空方法调用。
代码如下,也可在此要点中找到 - https://gist.github.com/piersy/23b4814eec806b584266
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestReflection {
public static long INC = 0;
public static final int COUNT = 100000000;
private static class Dummy {
public void doSomething(String s1, String s2, String s3) {
INC++;
}
}
public static void main(String[] args) throws NoSuchMethodException {
Dummy obj = new Dummy();
Method method = obj.getClass().getMethod("doSomething", String.class, String.class, String.class);
String s1 = "string1";
String s2 = "string2";
String s3 = "string3";
//warmup
runReflection(obj, method, s1, s2, s3, COUNT / 10);
runStatic(obj, s1, s2, s3, COUNT/10);
///realtest
long reftime = System.nanoTime();
runReflection(obj, method, s1, s2, s3, COUNT);
reftime = System.nanoTime() - reftime;
long time = System.nanoTime();
runStatic(obj, s1, s2, s3, COUNT);
time = System.nanoTime() - time;
System.out.println(reftime);
System.out.println(time);
//1000 *1000 *1000 nanoseconds in a second
System.out.println(reftime / (1000 *1000 *1000));
System.out.println(time / (1000 *1000 *1000));
System.out.println((double)reftime/ (double)time );
System.out.println("percentage speed decrease from using reflection:"+(((double)reftime/(double)time)-1)*100);
}
private static void runReflection(Dummy obj, Method method, String s1, String s2, String s3, int count) {
for (int i = 0; i < count; i++) {
try {
method.invoke(obj, s1, s2, s3);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
}
private static void runStatic(Dummy obj, String s1, String s2, String s3, int count) {
for (int i = 0; i < count; i++) {
obj.doSomething(s1,s2,s3);
}
}
}
答案 1 :(得分:1)
一般来说,是的,反射速度较慢。如果数以百万计的实例意味着数百万的呼叫,那么是的,在某些情况下,您可能会产生超过20秒的开销。在某些情况下,您可能不会产生额外的开销,因为编译器将能够优化它。您要么必须提供更多有关计划如何使用反射或自行运行的详细信息。我的GUT说,在300万次通话中,你不会产生超过20秒的开销,但这是非常直接的感觉。
答案 2 :(得分:0)
让我们从Oracle Docs
的反思开始反思的缺点
反思很强大,但不应随意使用。如果它 可以在不使用反射的情况下执行操作,然后执行操作 最好避免使用它。应保留以下问题 记住通过反射访问代码时。
性能开销因为反射涉及的类型 动态解析,某些Java虚拟机优化可以 不被执行。因此,反射操作较慢 性能比他们的非反光同行,应该是 在经常调用的代码段中避免使用 对性能敏感的应用程序。
安全限制 Reflection需要运行时权限,运行时可能不存在 在安全经理下。这是一个重要的考虑因素 必须在受限制的安全上下文中运行的代码,例如在 小应用程序。
内部曝光 由于反射允许代码执行在非反射代码中非法的操作,例如 访问私有字段和方法,可以导致使用反射 在意想不到的副作用,这可能导致代码功能失调和 可能会破坏便携性。反射代码打破了抽象和 因此可能会通过升级平台来改变行为。
因此,一旦开始扩展,您可以确保性能成为问题。 但是,如果您能够忍受直觉所说的大写/小写操作不应超过20秒的性能开销,并且可以大幅度扩展,那么您可以使用它。但请注意,对性能的直觉通常总是错误的。所以你想要测试一下。
为所需任务查找面向方面编程。
我的观点:使用AOP框架。