I was investigating if replacing a java.lang.reflect.Field.get
call with a VarHandle
would improve performance, but instead it got slower.
From benchmarking, I can see that when the VarHandle
is static
, it outperforms Field.get
(obviously) - but when it's not, it's about twice as slow.
For my use-case, it needs to generic across unknown classes - so not static - e.g. think about serialization.
Is there an alternative way to outperform Field.get
?
Benchmark:
import org.openjdk.jmh.annotations.*;import java.lang.invoke.*;import java.lang.reflect.Field;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 ReflectiveFieldAccessBenchmark { static { try { field = ReflectiveFieldAccessBenchmark.class.getDeclaredField("count"); } catch (final ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); } } private static final Field field; private static final VarHandle staticVarHandle = getVarHandle(); private final VarHandle nonStaticVarHandle = getVarHandle(); private final Number count = new AtomicInteger(Integer.MAX_VALUE); private static VarHandle getVarHandle() { try { return MethodHandles.lookup().unreflectVarHandle(field); } catch (final ReflectiveOperationException e) { throw new RuntimeException(e); } } @Benchmark public Object reflection() throws Exception { return field.get(this); } @Benchmark public Object staticVarHandle() throws Exception { return staticVarHandle.get(this); } @Benchmark public Object nonStaticVarHandle() throws Exception { return nonStaticVarHandle.get(this); }}
Output:
Benchmark Mode Cnt Score Error UnitsReflectiveFieldAccessBenchmark.nonStaticVarHandle avgt 1000 3.485 ± 0.005 ns/opReflectiveFieldAccessBenchmark.reflection avgt 1000 2.027 ± 0.002 ns/opReflectiveFieldAccessBenchmark.staticVarHandle avgt 1000 0.433 ± 0.002 ns/op