Java反射性能

Java反射性能,java,performance,optimization,reflection,Java,Performance,Optimization,Reflection,使用反射而不是调用类构造函数创建对象是否会导致任何显著的性能差异?是的,速度明显较慢。我们运行了一些这样做的代码,虽然我目前没有可用的度量标准,但最终的结果是我们必须重构代码以避免使用反射。如果您知道类是什么,只需直接调用构造函数即可。是-绝对是。通过反射查找类的成本从数量上看更高 引述: 由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。因此,反射式操作的性能比非反射式操作要慢,应该避免在性能敏感应用程序中频繁调用的代码段中使用反射式操作 下面是我在5分钟内完成的一个简单测试,运

使用反射而不是调用类构造函数创建对象是否会导致任何显著的性能差异?

是的,速度明显较慢。我们运行了一些这样做的代码,虽然我目前没有可用的度量标准,但最终的结果是我们必须重构代码以避免使用反射。如果您知道类是什么,只需直接调用构造函数即可。

是-绝对是。通过反射查找类的成本从数量上看更高

引述:

由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。因此,反射式操作的性能比非反射式操作要慢,应该避免在性能敏感应用程序中频繁调用的代码段中使用反射式操作

下面是我在5分钟内完成的一个简单测试,运行Sun JRE 6u10:

public class Main {

    public static void main(String[] args) throws Exception
    {
        doRegular();
        doReflection();
    }

    public static void doRegular() throws Exception
    {
        long start = System.currentTimeMillis();
        for (int i=0; i<1000000; i++)
        {
            A a = new A();
            a.doSomeThing();
        }
        System.out.println(System.currentTimeMillis() - start);
    }

    public static void doReflection() throws Exception
    {
        long start = System.currentTimeMillis();
        for (int i=0; i<1000000; i++)
        {
            A a = (A) Class.forName("misc.A").newInstance();
            a.doSomeThing();
        }
        System.out.println(System.currentTimeMillis() - start);
    }
}
请记住,查找和实例化是一起完成的,在某些情况下可以重构查找,但这只是一个基本示例

即使只是实例化,您仍然会获得性能上的影响:

30 // no reflection
47 // reflection using one lookup, only instantiating

同样,YMMV。

反射会带来一些开销,但在现代虚拟机上,它比以前小得多


如果您使用反射来创建程序中的每个简单对象,那么一定是出了问题。偶尔使用它,如果你有充分的理由,应该一点也不成问题。

是的,通过反射创建对象总是会比较慢,因为JVM无法在编译时优化代码。有关更多详细信息,请参阅Sun/Java

请参阅此简单测试:

public class TestSpeed {
    public static void main(String[] args) {
        long startTime = System.nanoTime();
        Object instance = new TestSpeed();
        long endTime = System.nanoTime();
        System.out.println(endTime - startTime + "ns");

        startTime = System.nanoTime();
        try {
            Object reflectionInstance = Class.forName("TestSpeed").newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        endTime = System.nanoTime();
        System.out.println(endTime - startTime + "ns");
    }
}
“重要”完全取决于上下文

如果您使用反射基于某个配置文件创建单个处理程序对象,然后将剩余的时间用于运行数据库查询,那么它就无关紧要了。如果你通过紧密循环中的反射来创建大量的对象,那么是的,这很重要


一般来说,设计灵活性(如果需要!)应该驱动您使用反射,而不是性能。但是,要确定性能是否是一个问题,您需要对其进行分析,而不是从讨论论坛上获得任意的响应。

通常您可以使用Apache commons BeanUtils或PropertyUtils进行内省(基本上,它们缓存有关类的元数据,因此不必总是使用反射).

您可能会发现JVM正在优化A=new A()。 如果将对象放入数组中,它们的性能将不太好。;) 下面的照片

new A(), 141 ns
A.class.newInstance(), 266 ns
new A(), 103 ns
A.class.newInstance(), 261 ns

public class Run {
    private static final int RUNS = 3000000;

    public static class A {
    }

    public static void main(String[] args) throws Exception {
        doRegular();
        doReflection();
        doRegular();
        doReflection();
    }

    public static void doRegular() throws Exception {
        A[] as = new A[RUNS];
        long start = System.nanoTime();
        for (int i = 0; i < RUNS; i++) {
            as[i] = new A();
        }
        System.out.printf("new A(), %,d ns%n", (System.nanoTime() - start)/RUNS);
    }

    public static void doReflection() throws Exception {
        A[] as = new A[RUNS];
        long start = System.nanoTime();
        for (int i = 0; i < RUNS; i++) {
            as[i] = A.class.newInstance();
        }
        System.out.printf("A.class.newInstance(), %,d ns%n", (System.nanoTime() - start)/RUNS);
    }
}
newa(),141 ns
A.class.newInstance(),266 ns
新的A(),103 ns
A.class.newInstance(),261 ns
公营课{
专用静态最终整数运行=3000000;
公共静态A类{
}
公共静态void main(字符串[]args)引发异常{
doRegular();
doReflection();
doRegular();
doReflection();
}
public static void doRegular()引发异常{
A[]as=新的A[运行];
长启动=System.nanoTime();
for(int i=0;i
这表明我的机器上的差异约为150纳秒。

是的,速度较慢

但请记住这条该死的规则——过早优化是万恶之源

(好的,可以用#1系在干燥处)

我发誓,如果有人在工作中来找我,问我这个问题,我会在接下来的几个月里对他们的代码保持高度警惕

在确定您需要它之前,您决不能进行优化,在这之前,只需编写好的、可读的代码

哦,我也不是说写愚蠢的代码。只要想一想你能做的最干净的方式——不复制和粘贴,等等(仍然要小心像内部循环和使用最适合你需要的集合这样的东西——忽略这些不是“未优化”的编程,而是“糟糕”的编程)

当我听到这样的问题时,我很害怕,但我忘了每个人都必须自己学习所有的规则才能真正理解。在你花了一个月的时间调试某人“优化”的东西之后,你就会得到它

编辑:

这条线发生了一件有趣的事情。检查#1答案,这是一个例子,说明编译器在优化方面有多么强大。该测试完全无效,因为可以完全排除非反射实例化

教训?在编写干净整洁的代码解决方案并证明其速度太慢之前,永远不要进行优化。

如果确实需要比反射更快的东西,而且这不仅仅是过早的优化,那么可以选择使用字节码生成或更高级别的库。第一次生成字节码比仅仅使用反射慢,但是一旦生成了字节码,它就和普通Java代码一样快,并且将由JIT编译器进行优化

使用代码生成的一些应用程序示例:

  • 在由生成的代理上调用方法的速度略快于Java,因为CGLIB为其代理生成字节码,但动态代理仅使用反射(CGLIB在方法调用中大约快10倍,但创建代理的速度较慢)

  • 生成字节码,用于读取/写入序列化对象的字段,而不是使用反射。在JSerial的网站上有很多

  • 我不是百分之百确定(我也不想看《灵魂》杂志)
    new A(), 141 ns
    A.class.newInstance(), 266 ns
    new A(), 103 ns
    A.class.newInstance(), 261 ns
    
    public class Run {
        private static final int RUNS = 3000000;
    
        public static class A {
        }
    
        public static void main(String[] args) throws Exception {
            doRegular();
            doReflection();
            doRegular();
            doReflection();
        }
    
        public static void doRegular() throws Exception {
            A[] as = new A[RUNS];
            long start = System.nanoTime();
            for (int i = 0; i < RUNS; i++) {
                as[i] = new A();
            }
            System.out.printf("new A(), %,d ns%n", (System.nanoTime() - start)/RUNS);
        }
    
        public static void doReflection() throws Exception {
            A[] as = new A[RUNS];
            long start = System.nanoTime();
            for (int i = 0; i < RUNS; i++) {
                as[i] = A.class.newInstance();
            }
            System.out.printf("A.class.newInstance(), %,d ns%n", (System.nanoTime() - start)/RUNS);
        }
    }
    
    new A(), 70 ns
    A.class.newInstance(), 214 ns
    new A(), 84 ns
    A.class.newInstance(), 229 ns
    
    new A(), 69 ns
    A.class.newInstance(), 159 ns
    new A(), 85 ns
    A.class.newInstance(), 171 ns
    
      Method md = null;     // Call while looking up the method at each iteration.
          millis = System.currentTimeMillis( );
          for (idx = 0; idx < CALL_AMOUNT; idx++) {
            md = ri.getClass( ).getMethod("getValue", null);
            md.invoke(ri, null);
          }
    
          System.out.println("Calling method " + CALL_AMOUNT+ " times reflexively with lookup took " + (System.currentTimeMillis( ) - millis) + " millis");
    
    
    
          // Call using a cache of the method.
    
          md = ri.getClass( ).getMethod("getValue", null);
          millis = System.currentTimeMillis( );
          for (idx = 0; idx < CALL_AMOUNT; idx++) {
            md.invoke(ri, null);
          }
          System.out.println("Calling method " + CALL_AMOUNT + " times reflexively with cache took " + (System.currentTimeMillis( ) - millis) + " millis");
    
    public class ReflectionTest extends TestCase {    
        @Test
        public void test_perf() {
            Profiler.run(3, 100000, 3, "m_01 by refelct", () -> Reflection.on(X.class)._new().invoke("m_01")).printResult();    
            Profiler.run(3, 100000, 3, "m_01 direct call", () -> new X().m_01()).printResult();    
            Profiler.run(3, 100000, 3, "m_02 by refelct", () -> Reflection.on(X.class)._new().invoke("m_02")).printResult();    
            Profiler.run(3, 100000, 3, "m_02 direct call", () -> new X().m_02()).printResult();    
            Profiler.run(3, 100000, 3, "m_11 by refelct", () -> Reflection.on(X.class)._new().invoke("m_11")).printResult();    
            Profiler.run(3, 100000, 3, "m_11 direct call", () -> X.m_11()).printResult();    
            Profiler.run(3, 100000, 3, "m_12 by refelct", () -> Reflection.on(X.class)._new().invoke("m_12")).printResult();    
            Profiler.run(3, 100000, 3, "m_12 direct call", () -> X.m_12()).printResult();
        }
    
        public static class X {
            public long m_01() {
                return m_11();
            }    
            public long m_02() {
                return m_12();
            }    
            public static long m_11() {
                long sum = IntStream.range(0, 10).sum();
                assertEquals(45, sum);
                return sum;
            }    
            public static long m_12() {
                long sum = IntStream.range(0, 10000).sum();
                assertEquals(49995000, sum);
                return sum;
            }
        }
    }