Performance Zone is brought to you in partnership with:

Peter is a DZone MVB and is not an employee of DZone and has posted 157 posts at DZone. You can read more from them at their website. View Full User Profile

MethodHandle performance in Java 7

09.01.2011
| 11420 views |
  • submit to reddit

A new feature in Java 7 provides a MethodHandle which "is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values"

This supports currying methods and many other features lambda based languages take for granted.

Example

Say you have two method
public static int multiply(int i, int j) {
    return i * j;
}

public static int subtract(int i, int j) {
    return i - j;
}
With MethodHandle you can not only get a reference to the Method (like in reflection) but you can construct new MethodHandles. For example, you can bind the Object concerned or one of the arguments.

final Lookup lookup = lookup();
MethodHandle multiply = lookup.findStatic(MethodHandleMain.class, "multiply", methodType(int.class, int.class, int.class));
MethodHandle quadruple = insertArguments(multiply, 1, 4);

System.out.println(multiply.invoke(3, 2)); // prints 6
System.out.println(quadruple.invoke(5)); // prints 20

MethodHandle subtract = lookup.findStatic(MethodHandleMain.class, "subtract", methodType(int.class, int.class, int.class));
MethodHandle subtractFromFour = insertArguments(subtract, 0, 4);
MethodHandle fourLess = insertArguments(subtract, 1, 4);
System.out.println(subtract.invoke(10, 5)); // prints 5
System.out.println(subtractFromFour.invoke(10)); // prints -6
System.out.println(fourLess.invoke(10)); // prints 6

Performance

This is very cool, but how does it perform? ;)

There is a lot of potential for it to perform very well and the interface is cleaner than plain reflections however when comparing the alternatives, it doesn't perform as well as the alternatives in Java 7 (update 0)
Call methodAverage time per call
Direct Method calls31 ns
Reflections353 ns
MethodHandle.invoke()5,378 ns
It is a very cool API and hopefully it will perform much better in the future. ;)

The code

MethodHandleTest.java

 

From http://vanillajava.blogspot.com/2011/08/methodhandle-performance-in-java-7.html

Published at DZone with permission of Peter Lawrey, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Jonathan Fisher replied on Fri, 2011/09/02 - 9:05am

One thing I noticed about reflection is that for the first couple thousand invocations, reflection is about an order of magnitude slower. Then suddenly, a massive JIT burp happens and my methods are closer to normal speed. Any chance that MethodHandle would have the same characteristics?

Arnaud Des_vosges replied on Fri, 2011/09/02 - 10:26am

"and many other features lambda based languages take for granted"
but without the performance java developers take for granted

:))

By removing the autoboxing on method call:

      public static Integer multiply(Integer i, Integer j) {
        return i * j;
      }

      public static Integer subtract(Integer i, Integer j) {
        return i - j;
      }

I can see theses results which show more clearly the relative overhead of Reflection:

- Direct call Average call time was 46
- Method Average call time was 167

 (don't have JDK 1.7 installed for MethodHandle test,  sorry)

 

Endre Varga replied on Sat, 2011/09/03 - 8:11am

Isn't that the case, that MethodHandle calls are optimized for linking them with invokedynamic callsites? What is the performance characteristic of them, when they are linked?

John David replied on Thu, 2012/01/26 - 3:21am

It would make a lot more sense if it also had syntax support in the compiler, i.e. something the compiler might check, e.g.:

final MethodHandle add = Example.class.method.add(int,int);

assert 8 == add.invoke(3, 5);

Java Eclipse

Emmanuel Castro replied on Mon, 2012/05/21 - 5:26am

MethodHandle not so slow

 

I tried the code on:

java version "1.7.0_03"
OpenJDK Runtime Environment (IcedTea7 2.1.1pre) (7~u3-2.1.1~pre1-1ubuntu3)
OpenJDK Client VM (build 22.0-b10, mixed mode, sharing)
  I get the same figure as below: 
  • Direct call Average call time was 36
  • Method Average call time was 539
  • Method Handle Average call time was 24 475 

 However, if I use invokeExact instead of invoke, MethodHandle are fast the traditionnal reflection (Method). 

  • Direct call Average call time was 35
  • Method Average call time was 524
  • Method Handle Average call time was 52  
 The code is nearly the same. I just changed (line 43) :

 

        for (int i = 0; i < runs; i += 5) {
            sum += (Integer) multiply.invoke(i, i) +
                    (Integer) quadruple.invoke(i) +
                    (Integer) subtract.invoke(i, 1) +
                    (Integer) subtractFromFour.invoke(i) +
                    (Integer) fourLess.invoke(i);
        } 

by : 

        for (int i = 0; i < runs; i += 5) {
            sum += (int) multiply.invokeExact((int)i, (int)i) +
                (int) quadruple.invokeExact((int)i) +
               (int) subtract.invokeExact((int)i, (int)1) +
               (int) subtractFromFour.invokeExact((int)i) +
               (int) fourLess.invokeExact((int)i);
       } 

Note that invokeExact required explicit typing, which would be useless for other Java methods. Some IDE may report errors (cannot cast Object to int). It is OK for Javac.

Conclusion  

  • MethodHandle.invokeExact is really faster than Method.invoke.
  • MethodHandke.invoke does a lot of work in order to convert Object or Integer to int and back again. It is not efficient yet, may be in next releases of HotSpot.
  • MethodHandle.invokeExact require precise argument signature at the call site. 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.