I would like to call a method via reflection in the most performant way possible.
The method returns an Object.
I've implemented this using both reflection and MethodHandles, I was expecting MethodHandle to be faster - but that's not what I'm seeing (~20-40% slower).
Take the following JMH benchmark:
import org.openjdk.jmh.annotations.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 200, time = 10, timeUnit = TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class AccessorBenchmark {
private static final Object[] EMPTY_ARGS = new Object[0];
private POJO source;
private Method method;
private MethodHandle methodHandle;
private MethodHandle methodHandleModifiedReturnType;
@Setup
public void setup() throws ReflectiveOperationException {
source = new POJO();
method = source.getClass().getDeclaredMethod("getNumber");
methodHandle = MethodHandles.lookup().unreflect(method);
methodHandleModifiedReturnType = methodHandle.asType(methodHandle.type().changeReturnType(Number.class));
}
@Benchmark
public Number reflection() throws Throwable {
return (Number) method.invoke(source, EMPTY_ARGS);
}
@Benchmark
public Number methodHandle() throws Throwable {
return (Number) methodHandle.invoke(source);
}
@Benchmark
public Number methodHandleInvokeExact() throws Throwable {
return (Number) methodHandleModifiedReturnType.invokeExact(source);
}
public class POJO {
private final AtomicInteger counter = new AtomicInteger();
public AtomicInteger getNumber() {
return counter;
}
}
}
The following result is returned with Java 17:
Benchmark Mode Cnt Score Error Units
AccessorBenchmark.methodHandle avgt 1000 2.856 ± 0.004 ns/op
AccessorBenchmark.methodHandleInvokeExact avgt 1000 2.359 ± 0.003 ns/op
AccessorBenchmark.reflection avgt 1000 2.017 ± 0.002 ns/op
Any ideas?
Aucun commentaire:
Enregistrer un commentaire