Faster Alternatives to Java's Reflection

Faster alternatives to Java's reflection

One alternative to Reflection is to generate a class file dynamically. This generated class ought to perform the desired action, e.g. invokes the method discovered at runtime, and implements an interface known at compile-time so that it’s possible to invoke the generated method in a non-reflective way using that interface. There’s one catch: if applicable, Reflection does the same trick internally. This does not work in special cases, e.g. when invoking a private method as you can’t generate a legal class file invoking it. So in the Reflection implementation there are different types of invocation handlers, using either generated code or native code. You can’t beat that.

But more important is that Reflection does security checks on every invocation. So your generated class will be checked on loading and instantiation only which can be a big win. Alternatively you can invoke setAccessible(true) on a Method instance to turn the security checks off. Then only the minor performance loss of autoboxing and varargs array creation remains.

Since Java 7 there is an alternative to both, the MethodHandle. The big advantage is that, unlike the other two, it even works in security restricted environments. The access checks for a MethodHandle are performed when acquiring it but not when invoking it. It has the so-called “polymorphic signature” which means you can invoke it with arbitrary argument types without auto-boxing nor array creation. Of course, wrong argument types will create an appropriate RuntimeException.

(Update)
With Java 8, there is the option to use the back-end of the lambda expression and method reference language feature at runtime. This backend does exactly the thing described at the beginning, generating a class dynamically which implements an interface your code may call directly when it is known at compile-time. The exact mechanics is implementation-specific, hence undefined, but you can assume that the implementation will try it’s best to make the invocation as fast as possible. The current implementation of Oracle’s JRE does it perfectly. Not only that this saves you from the burden of generating such an accessor class, it is also capable of doing what you never could do— invoke even private methods via generated code. I have updated the example to include this solution. This example uses a standard interface which already exists and happens to have the desired method signature. If no such matching interface exists, you have to create your own accessor functional interface with a method with the right signature. But, of course, now the example code requires Java 8 to run.

Here is a simple benchmark example:

import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.function.IntBinaryOperator;

public class TestMethodPerf
{
private static final int ITERATIONS = 50_000_000;
private static final int WARM_UP = 10;

public static void main(String... args) throws Throwable
{
// hold result to prevent too much optimizations
final int[] dummy=new int[4];

Method reflected=TestMethodPerf.class
.getDeclaredMethod("myMethod", int.class, int.class);
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh=lookup.unreflect(reflected);
IntBinaryOperator lambda=(IntBinaryOperator)LambdaMetafactory.metafactory(
lookup, "applyAsInt", MethodType.methodType(IntBinaryOperator.class),
mh.type(), mh, mh.type()).getTarget().invokeExact();

for(int i=0; i<WARM_UP; i++)
{
dummy[0]+=testDirect(dummy[0]);
dummy[1]+=testLambda(dummy[1], lambda);
dummy[2]+=testMH(dummy[1], mh);
dummy[3]+=testReflection(dummy[2], reflected);
}
long t0=System.nanoTime();
dummy[0]+=testDirect(dummy[0]);
long t1=System.nanoTime();
dummy[1]+=testLambda(dummy[1], lambda);
long t2=System.nanoTime();
dummy[2]+=testMH(dummy[1], mh);
long t3=System.nanoTime();
dummy[3]+=testReflection(dummy[2], reflected);
long t4=System.nanoTime();
System.out.printf("direct: %.2fs, lambda: %.2fs, mh: %.2fs, reflection: %.2fs%n",
(t1-t0)*1e-9, (t2-t1)*1e-9, (t3-t2)*1e-9, (t4-t3)*1e-9);

// do something with the results
if(dummy[0]!=dummy[1] || dummy[0]!=dummy[2] || dummy[0]!=dummy[3])
throw new AssertionError();
}

private static int testMH(int v, MethodHandle mh) throws Throwable
{
for(int i=0; i<ITERATIONS; i++)
v+=(int)mh.invokeExact(1000, v);
return v;
}

private static int testReflection(int v, Method mh) throws Throwable
{
for(int i=0; i<ITERATIONS; i++)
v+=(int)mh.invoke(null, 1000, v);
return v;
}

private static int testDirect(int v)
{
for(int i=0; i<ITERATIONS; i++)
v+=myMethod(1000, v);
return v;
}

private static int testLambda(int v, IntBinaryOperator accessor)
{
for(int i=0; i<ITERATIONS; i++)
v+=accessor.applyAsInt(1000, v);
return v;
}

private static int myMethod(int a, int b)
{
return a<b? a: b;
}
}

Th old program printed in my Java 7 setup: direct: 0,03s, mh: 0,32s, reflection: 1,05s which suggested that MethodHandle was a good alternative. Now, the updated program running under Java 8 on the same machine printed direct: 0,02s, lambda: 0,02s, mh: 0,35s, reflection: 0,40s which clearly shows that Reflection performance has been improved to a degree that might make dealing with MethodHandle unnecessary, unless you use it to do the lambda trick, that clearly outperforms all reflective alternatives, which comes at no surprise, as it is just a direct call (well, almost: one level of indirection). Note that I made the target method private to demonstrate the capability of calling even private methods efficiently.

As always, I have to point at the simplicity of this benchmark and how artificial it is. But I think, the tendency is clearly visible and even more important, the results are convincingly explainable.

Better alternative to reflection than large switch statement using java 8

EDIT:

This can be simplified indeed as Holger suggests:

 Map<String, BiFunction<ByteBuffer, Integer, AbstractID3v2FrameBody>> LOOKUP = Map.of(
FRAME_ID_AUDIO_ENCRYPTION, FrameBodyAENC::new,
FRAME_ID_ATTACHED_PICTURE, FrameBodyAPIC::new
);

And then as simple as:

LOOKUP.get(ID3v24Frames.FRAME_ID_AUDIO_ENCRYPTION)
.apply(byteBuffer, frameSize);

PREVIOUS SUGGESTION

This is just a sample, you will need to adapt it to your classes:

private static final Lookup L = MethodHandles.lookup();
private static final MethodHandle CONS;

static {
try {
CONS = L.findConstructor(SomeClass.class, MethodType.methodType(void.class, int.class));
} catch (Throwable t) {
throw new RuntimeException(t);
}
}

private static final Map<String, MethodHandle> LOOK_UP = Map.of(
"SOME_CLASS", CONS
);

public static void main(String[] args) {

try {
SomeClass sc = (SomeClass) LOOK_UP.get("SOME_CLASS").invokeExact(42);
System.out.println(sc.getX());
} catch (Throwable t) {
t.printStackTrace();
}

}

static class SomeClass {

private final int x;

public SomeClass(int x) {
this.x = x;
}

public int getX() {
return x;
}
}

Java Reflection Performance

Yes - absolutely. Looking up a class via reflection is, by magnitude, more expensive.

Quoting Java's documentation on reflection:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

Here's a simple test I hacked up in 5 minutes on my machine, running 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);
}
}

With these results:

35 // no reflection
465 // using reflection

Bear in mind the lookup and the instantiation are done together, and in some cases the lookup can be refactored away, but this is just a basic example.

Even if you just instantiate, you still get a performance hit:

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

Again, YMMV.

Is it OK to use reflection in frequently done operations methods?

If you can avoid reflection in frequently-called methods, do avoid it. The problem is, however, than you often really need some kind of reflected invocation so there are cases where you simply can't avoid reflection.

The question is then not really if you should or should not use reflected invocations but rather if and how you should optimize such calls.

For this, please see the following post:

Faster alternatives to Java's reflection

This answer suggests that reflection performance in Java 8 was quite improved. So before you start optimizing anything, it would make sense to run some benchmarks or do some profiling (run a lot of iterations) to make sure that it's really reflection which eats your performance.

Hint: it is mostly not.

Anyway, I won't really worry about reflection performance. There are very good techniques to improve performance of reflected invocations which even don't need much code changes. See this blog post, for instance for example of using LambdaMetafactory to almost achieve the performance of direct invocations. If you worry about performance, it might make sense to implement reflected invocations in some kind of utility class/method centrally so that you could reimplement/improve it later on in just one place.

Java Reflection: the fast way to retrieve value from property

There are different levels in there:

  • A field access is a field access. A method that access the field will ... access the field, too. Just with much more overhead.
  • You have to maintain your code over time.

The first point suggests that a "straight forward" field access should always be faster (especially given the fact that this method is pretty short - and the JIT is much better at inlining short methods). Leading to the second point: simply ask yourself which of the three methods is the easiest to read and understand.

The key thing is that reflection calls are expensive. The method handle concept is intended to improve that cost (by avoiding the checks that a method call using reflection is undergoing each time). So if you are really interested in finding the "optimal" code, then the answer might be framed around a solution that computes a method handle once, to then be re-used for subsequent calls. There is absolutely no point in instantiating a method handle just to make a single call. Nothing to be gained from that - method handles are "cheaper" than ordinary reflection only when you repeatedly use the method handle to make calls.

Of course, the real answer is: you step back, you learn how to correctly benchmark java code, and then you do a bit of measuring within your context, environment - your data, your code. To then draw your final conclusion. And I also agree with the comment given by spi - if performance is crucial to you, then reflection is (more or less) a no go.

How can I improve performance of Field.set (perhap using MethodHandles)?

2015-06-01: Updated to reflect @JoeC's comment about another case when handles are static. Also updated to latest JMH and re-ran on modern hardware. The conclusion stays almost the same.

Please do proper benchmarking, it is arguably not that hard with JMH. Once you do that, the answer becomes obvious. It can also showcase the proper use of invokeExact (requires target/source 1.7 to compile and run):

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class MHOpto {

private int value = 42;

private static final Field static_reflective;
private static final MethodHandle static_unreflect;
private static final MethodHandle static_mh;

private static Field reflective;
private static MethodHandle unreflect;
private static MethodHandle mh;

// We would normally use @Setup, but we need to initialize "static final" fields here...
static {
try {
reflective = MHOpto.class.getDeclaredField("value");
unreflect = MethodHandles.lookup().unreflectGetter(reflective);
mh = MethodHandles.lookup().findGetter(MHOpto.class, "value", int.class);
static_reflective = reflective;
static_unreflect = unreflect;
static_mh = mh;
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}

@Benchmark
public int plain() {
return value;
}

@Benchmark
public int dynamic_reflect() throws InvocationTargetException, IllegalAccessException {
return (int) reflective.get(this);
}

@Benchmark
public int dynamic_unreflect_invoke() throws Throwable {
return (int) unreflect.invoke(this);
}

@Benchmark
public int dynamic_unreflect_invokeExact() throws Throwable {
return (int) unreflect.invokeExact(this);
}

@Benchmark
public int dynamic_mh_invoke() throws Throwable {
return (int) mh.invoke(this);
}

@Benchmark
public int dynamic_mh_invokeExact() throws Throwable {
return (int) mh.invokeExact(this);
}

@Benchmark
public int static_reflect() throws InvocationTargetException, IllegalAccessException {
return (int) static_reflective.get(this);
}

@Benchmark
public int static_unreflect_invoke() throws Throwable {
return (int) static_unreflect.invoke(this);
}

@Benchmark
public int static_unreflect_invokeExact() throws Throwable {
return (int) static_unreflect.invokeExact(this);
}

@Benchmark
public int static_mh_invoke() throws Throwable {
return (int) static_mh.invoke(this);
}

@Benchmark
public int static_mh_invokeExact() throws Throwable {
return (int) static_mh.invokeExact(this);
}

}

On 1x4x2 i7-4790K, JDK 8u40, Linux x86_64 it yields:

Benchmark                             Mode  Cnt  Score   Error  Units
MHOpto.dynamic_mh_invoke avgt 25 4.393 ± 0.003 ns/op
MHOpto.dynamic_mh_invokeExact avgt 25 4.394 ± 0.007 ns/op
MHOpto.dynamic_reflect avgt 25 5.230 ± 0.020 ns/op
MHOpto.dynamic_unreflect_invoke avgt 25 4.404 ± 0.023 ns/op
MHOpto.dynamic_unreflect_invokeExact avgt 25 4.397 ± 0.014 ns/op
MHOpto.plain avgt 25 1.858 ± 0.002 ns/op
MHOpto.static_mh_invoke avgt 25 1.862 ± 0.015 ns/op
MHOpto.static_mh_invokeExact avgt 25 1.859 ± 0.002 ns/op
MHOpto.static_reflect avgt 25 4.274 ± 0.011 ns/op
MHOpto.static_unreflect_invoke avgt 25 1.859 ± 0.002 ns/op
MHOpto.static_unreflect_invokeExact avgt 25 1.858 ± 0.002 ns/op

...which suggests MH are really much faster than Reflection in this particular case (this is because the access checks against the private field is done at lookup time, and not at the invocation time). dynamic_* cases simulate the case when the MethodHandles and/or Fields are not statically known, e.g. pulled from Map<String, MethodHandle> or something like it. Conversely, static_* cases are those where the invokers are statically known.

Notice the reflective performance is on par with MethodHandles in dynamic_* cases, this is because reflection is heavily optimized further in JDK 8 (because really, you don't need the access check to read your own fields), so the answer may be "just" switching to JDK 8 ;)

static_* cases are even faster, because the MethoHandles.invoke calls are aggressively inlined. This eliminates part of the type checking in MH cases. But, in reflection cases, there are still quick checks present, and therefore, it lags behind.

Any difference between using method.invoke and just run the method for a public method in java?

To quote the official tutorial:

Reflection provides a means for invoking methods on a class. Typically, this would only be necessary if it is not possible to cast an instance of the class to the desired type in non-reflective code. Methods are invoked with java.lang.reflect.Method.invoke().

And you know the Direct way is just to initialize the class and call the method.



Related Topics



Leave a reply



Submit