Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the execution of a method fetched by Reflection take longer?

As you all know it is possible to fetch a method with Reflection and invoke it through the returned Method instance.

My question is however; once it is fetched by Reflection and I invoke the Method over and over again will the performance of the method be slower than the normal way of calling a method?

For example:

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();
        }
    }
}

I am asking this because I am making an event system that, upon registering the listener it scans for annotations. The methods are put into a map and then they are executed each time an event occurs of their required parameter type. I don't know if this is performant enough for, for example a game.

like image 453
Limnic Avatar asked Jan 12 '15 02:01

Limnic


2 Answers

Using the method without reflection is about an order of magnitude faster. I tested it like

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);
}

I also moved test to a static field so it would compile and run

private static Method test;
static {
    try {
        test = ReflectionTest.class.getMethod("testMethod");
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    }
}

I get a fairly consistent difference (or an output consistent) with

4526 606

Which indicates that across 10000 invocations reflection is ~7 times slower then direct invocation.

like image 101
Elliott Frisch Avatar answered Nov 15 '22 12:11

Elliott Frisch


@Elliot Frisch's answer provides conclusive1 evidence that using Method.invoke() is slower.

You would expect this anyway, because the reflective version involves extra work; e.g.

  • the creation and initialization of an array containing the varags,
  • checking the length of the array, and
  • casting the arguments in the array from Object to the respective parameter types.

It is possible that the JIT could could optimize this in some cases ...


1 - OK ... inconclusive. The benchmark is questionable because it doesn't take proper care to deal with possible JVM warmup anomalies.

like image 27
Stephen C Avatar answered Nov 15 '22 11:11

Stephen C