解释Java反射性能:为什么它惊人地快?
我见过其他线程说java反射性能比使用非反射调用慢10-100倍 我在1.6中的测试表明情况并非如此,但我发现了一些其他有趣的事情,需要有人向我解释 我有实现接口的对象。我做了三件事1)使用对对象的引用我将该对象转换到接口并通过接口调用该方法2)使用对实际对象的引用直接调用该方法,3)通过反射调用该方法。我看到#1接口调用最快,紧随其后的是#3反射,但我注意到直接方法调用最慢,相差很大 我不明白,我本以为直接调用会最快,然后接口,然后反射会慢得多 Blah和ComplexClass与主类位于不同的包中,它们都有一个doSomething(intx)方法,该方法实现接口并只打印整数x 以下是我的结果(以毫秒为单位的次数,结果非常相似/多次试验): 直接调用方法:107194 直接从对象转换到接口调用方法:89594 通过反射调用方法:90453 这是我的密码:解释Java反射性能:为什么它惊人地快?,java,performance,reflection,interface,Java,Performance,Reflection,Interface,我见过其他线程说java反射性能比使用非反射调用慢10-100倍 我在1.6中的测试表明情况并非如此,但我发现了一些其他有趣的事情,需要有人向我解释 我有实现接口的对象。我做了三件事1)使用对对象的引用我将该对象转换到接口并通过接口调用该方法2)使用对实际对象的引用直接调用该方法,3)通过反射调用该方法。我看到#1接口调用最快,紧随其后的是#3反射,但我注意到直接方法调用最慢,相差很大 我不明白,我本以为直接调用会最快,然后接口,然后反射会慢得多 Blah和ComplexClass与主类位于不同
public class Main
{
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
Blah x = new Blah();
ComplexClass cc = new ComplexClass();
test((Object) x, cc);
}
public static void test(Object x, ComplexClass cc)
{
long start, end;
long time1, time2, time3 = 0;
int numToDo = 1000000;
MyInterface interfaceClass = (MyInterface) x;
//warming up the cache
for (int i = 0; i < numToDo; i++)
{
cc.doSomething(i); //calls a method directly
}
start = System.currentTimeMillis();
for (int i = 0; i < numToDo; i++)
{
cc.doSomething(i); //calls a method directly
}
end = System.currentTimeMillis();
time1 = end - start;
start = System.currentTimeMillis();
for (int i = 0; i < numToDo; i++)
{
interfaceClass.doSomething(i); //casts an object to an interface then calls the method
}
end = System.currentTimeMillis();
time2 = end - start;
try
{
Class xClass = x.getClass();
Class[] argTypes =
{
int.class
};
Method m = xClass.getMethod("doSomething", argTypes);
Object[] paramList = new Object[1];
start = System.currentTimeMillis();
for (int i = 0; i < numToDo; i++)
{
paramList[0] = i;
m.invoke(x, paramList); //calls via reflection
}
end = System.currentTimeMillis();
time3 = end - start;
} catch (Exception ex)
{
}
System.out.println("calling a method directly: " + time1);
System.out.println("calling a method directly from an object cast to an interface: " + time2);
System.out.println("calling a method through reflection: " + time3);
}
公共类主
{
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args)
{
Blah x=新的Blah();
ComplexClass cc=新的ComplexClass();
测试((对象)x,cc);
}
公共静态无效测试(对象x,ComplexClass cc)
{
漫长的开始,漫长的结束;
长时间1,时间2,时间3=0;
int numToDo=1000000;
MyInterface interfaceClass=(MyInterface)x;
//预热缓存
对于(int i=0;i
将所有测试放在同一个程序中是一个微基准标记错误-Java性能有一定的预热。这是最重要的失败
把你的测试放在不同的程序中,然后运行测试几次,这样你就能感觉到热身什么时候结束以及统计意义
还有一个包含内部循环的巨大方法。Hotspot似乎比以前更擅长处理这个问题,但它仍然不太好
您应该会发现,使用
-server
调用虚拟方法(即使是由不同的类加载器加载)在紧循环中,会得到完全优化。因此,说直接调用比反射调用快多少没有多大意义。首先,反射在最新的JDK中快得多。其次,我预计热点编译器将优化所有这些调用,使其大致与代码一致。它可以对r进行运行时分析使您反复调用同一个函数,这样它就可以优化反射(和虚拟函数调用).与接口示例相同。我的测试表明,如果java能够内联函数,直接调用可以非常快。内联直接调用比反射调用快200-300倍。在ubuntu 12.10、Jdk 1.6.35、CPU Xeon E5-2620上测试
Java每天都在变得越来越智能
import java.lang.reflect.Method;
public class Main
{
static class Test
{
int i=0;
public void set(int value){
this.i = value;
}
}
public static void main( String[] args) throws Exception
{
Test test = new Test();
int max = 10000000;
long direct = System.currentTimeMillis();
for( int i=0; i<max; i++){
Integer io = new Integer(i*i);
test.set(io);
}
System.out.println("Direct : " + (System.currentTimeMillis() - direct));
Method method = Test.class.getMethod("set", Integer.TYPE);
long reflection = System.currentTimeMillis();
for( int i=0; i<max; i++){
Integer io = new Integer(i*i);
method.invoke(test, io );
}
System.out.println("Reflection : " + ( System.currentTimeMillis() - reflection));
}
}
import java.lang.reflect.Method;
公共班机
{
静态类测试
{
int i=0;
公共无效集(int值){
这个。i=值;
}
}
公共静态void main(字符串[]args)引发异常
{
测试=新测试();
int max=10000000;
long direct=System.currentTimeMillis();
对于(int i=0;iWHy CW?这是一个有效的非主观编程相关问题?为什么投票要结束?!我把标题变成了一个问题,问那些除非有标记否则看不到问题的人。但是,社区维基??你说有一个包含内部循环的巨大方法是什么意思?你是说测试方法本身太大了吗这是一个问题吗?什么是-服务器?我明白你的观点,每个测试都不在它们自己的方法中。虽然我有一种感觉,我会看到类似的结果。我可能会在得到这些结果后发表一篇单独的文章。你有一个大的测试方法,它会循环数百万次。-服务器是速度更快的switch(但会增加启动时间,并且不一定存在,尤其是在Windows JRE上)。测试应该在其自己的进程中。为每个测试重新运行程序。