Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Understand the performance impact of reflection
import com.google.common.collect.ImmutableMap;
import com.google.common.math.Stats;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ReflectionTest {
public interface FooGetter {
String getFoo();
}
public static class Foo implements FooGetter{
public String getFoo() {
return "foo";
}
}
public static void main(String[] args)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
final int numTrials = 100;
final int warmupBuffer = 10;
FooGetter getFoo = new Foo();
Map<Class, FooGetter> getterMap = ImmutableMap.of(Foo.class, getFoo);
List<Long> getTimesNoReflection = new ArrayList<>(numTrials);
for (int i = 0; i < numTrials + warmupBuffer; i++) {
long startTime = System.nanoTime();
getterMap.get(Foo.class).getFoo();
getTimesNoReflection.add(System.nanoTime() - startTime);
}
List<Long> getTimesReflection = new ArrayList<>(numTrials);
for (int i = 0; i < numTrials + warmupBuffer; i++) {
long startTime = System.nanoTime();
Foo.class.getMethod("getFoo").invoke(getFoo);
getTimesReflection.add(System.nanoTime() - startTime);
}
getTimesNoReflection = getTimesNoReflection.subList(warmupBuffer, getTimesNoReflection.size());
getTimesReflection = getTimesReflection.subList(warmupBuffer, getTimesReflection.size());
double logMeanParseTime = Math.log10(Stats.of(getTimesNoReflection).mean());
double logMeanConvertTime = Math.log10(Stats.of(getTimesReflection).mean());
System.out.printf("without reflection: %s | %f%n", Stats.of(getTimesNoReflection).toString(), logMeanParseTime);
System.out.printf("with reflection: %s | %f%n", Stats.of(getTimesReflection).toString(), logMeanConvertTime);
// output:
// without reflection: Stats{count=100, mean=613.9799999999997, populationStandardDeviation=665.633637671655, min=386.0, max=4904.0} | 2.788154
// with reflection: Stats{count=100, mean=29551.36000000001, populationStandardDeviation=240902.67234032584, min=3358.0, max=2425919.0} | 4.470577
}
}
@menendezau
Copy link

menendezau commented Jun 4, 2018

I added a third metric, which buffers the Method so that getMethod gets invoked only once. Got interesting results.

without reflection:  Stats{count=100, mean=336.14000000000004, populationStandardDeviation=12.276823693447747, min=316.0, max=390.0} | 2.526520
with reflection:     Stats{count=100, mean=24407.649999999987, populationStandardDeviation=203416.4143484677, min=2603.0, max=2048200.0} | 4.387526
with semi-reflection:Stats{count=100, mean=610.8799999999999, populationStandardDeviation=195.65629455757357, min=434.0, max=1863.0} | 2.785956

Full source:

import com.google.common.collect.ImmutableMap;
import com.google.common.math.Stats;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ReflectionTest {

    public interface  FooGetter {
        String getFoo();
    }

    public static class Foo implements FooGetter{
        public String getFoo() {
            return "foo";
        }
    }

    public static void main(String[] args)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        final int numTrials = 100;
        final int warmupBuffer = 10;

        FooGetter getFoo = new Foo();
        Map<Class<?>, FooGetter> getterMap = ImmutableMap.of(Foo.class, getFoo);


        List<Long> getTimesNoReflection = new ArrayList<>(numTrials);
        for (int i = 0; i < numTrials + warmupBuffer; i++) {
            long startTime = System.nanoTime();
            getterMap.get(Foo.class).getFoo();
            getTimesNoReflection.add(System.nanoTime() - startTime);
        }

        List<Long> getTimesReflection = new ArrayList<>(numTrials);
        for (int i = 0; i < numTrials + warmupBuffer; i++) {
            long startTime = System.nanoTime();
            Foo.class.getMethod("getFoo").invoke(getFoo);
            getTimesReflection.add(System.nanoTime() - startTime);
        }

        List<Long> getTimesSemiReflection = new ArrayList<>(numTrials);
        Method m = Foo.class.getMethod("getFoo");
        for (int i = 0; i < numTrials + warmupBuffer; i++) {
            long startTime = System.nanoTime();
            m.invoke(getFoo);
            getTimesSemiReflection.add(System.nanoTime() - startTime);
        }

        getTimesNoReflection = getTimesNoReflection.subList(warmupBuffer, getTimesNoReflection.size());
        getTimesReflection = getTimesReflection.subList(warmupBuffer, getTimesReflection.size());
        getTimesSemiReflection = getTimesSemiReflection.subList(warmupBuffer, getTimesSemiReflection.size());

        double logMeanParseTime = Math.log10(Stats.of(getTimesNoReflection).mean());
        double logMeanConvertTime = Math.log10(Stats.of(getTimesReflection).mean());
        double logMeanSemiTime = Math.log10(Stats.of(getTimesSemiReflection).mean());
        System.out.printf("without reflection:  %s | %f%n", Stats.of(getTimesNoReflection).toString(), logMeanParseTime);
        System.out.printf("with reflection:     %s | %f%n", Stats.of(getTimesReflection).toString(), logMeanConvertTime);
        System.out.printf("with semi-reflection:%s | %f%n", Stats.of(getTimesSemiReflection).toString(), logMeanSemiTime);

        // output:
        // without reflection:  Stats{count=100, mean=336.14000000000004, populationStandardDeviation=12.276823693447747, min=316.0, max=390.0} | 2.526520
        // with reflection:     Stats{count=100, mean=24407.649999999987, populationStandardDeviation=203416.4143484677, min=2603.0, max=2048200.0} | 4.387526
        // with semi-reflection:Stats{count=100, mean=610.8799999999999, populationStandardDeviation=195.65629455757357, min=434.0, max=1863.0} | 2.785956
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment