0

I have two performance tests using JMH. The code is very easy,one is using Java Reflection,Another is using MethodHandle(Introduced in JDK1.7),By The way,isEmptyMethod and MH_isEmpty is declared as static final,like this:

private static final MethodHandle MH_isEmpty;
private static final Method isEmptyMethod;

static {
    try {
        MH_isEmpty = MethodHandles.publicLookup().findVirtual(String.class, "isEmpty", MethodType.methodType(boolean.class));
        isEmptyMethod = String.class.getDeclaredMethod("isEmpty");
    } catch (Exception ex) {
        throw new UnsupportedOperationException();
    }
}

` Java Reflection:

@BenchmarkMode(Mode.Throughput)
public void testReflectionGetIsEmpty() throws Exception {
    isEmptyMethod.setAccessible(false);
    final Object result = isEmptyMethod.invoke("SmartLee");
}

` MethodHandle:

@Benchmark
@BenchmarkMode(Mode.Throughput)
public void testFindVirtual() throws Throwable {
    final MethodHandle isEmpty = MH_isEmpty.bindTo("SmartLee");
    isEmpty.invoke();
}

Beblow is the performance results: performance results

According to JDK docs.Why MethodHandle is not faster than java reflection? What's wrong with above code?

  • 1
    `MH_isEmpty.bindTo("SmartLee");` will create a new `MethodHandle`. Every time. Try `boolean result = (boolean) MH_isEmpty.invokeExact("SmartLee");`. Also, your reflection test may not be actually calling the method - it might be determined that it has no side effects. You should return the result of of the invocation. And parameterize it - in your current setup the JIT might reduce the code to a simple `return true` otherwise. – Johannes Kuhn Jul 24 '20 at 06:31
  • Thanks,Johannes. I add some log message that will 'consume' the result. And This will prevent JIT optimization.Now the result is intended.Thanks again for your advice. – 李建强 Jul 27 '20 at 06:02
  • 1. @Benchmark() @BenchmarkMode(Mode.Throughput) void testReflectionGetIsEmpty() throws Exception { isEmptyMethod.setAccessible(false); final Object result = isEmptyMethod.invoke("SmartLee"); log.info("The result of testReflectionGetIsEmpty is:{}",result); } 2. @Benchmark @BenchmarkMode(Mode.Throughput) void testFindVirtual() throws Throwable { final MethodHandle isEmpty = MH_isEmpty.bindTo("SmartLee"); Object result = isEmpty.invoke(); log.info("The result of testFindVirtual is:{}",result); } – 李建强 Jul 27 '20 at 06:06
  • And 3 this the performance result. It is now intended.3.Benchmark Mode Cnt Score Error Units JMHSample_01_HelloWorld.testFindVirtual thrpt 5 26213.457 ± 21430.137 ops/s JMHSample_01_HelloWorld.testReflectionGetIsEmpty thrpt 5 23876.432 ± 29526.599 ops/s JMHSample_01_HelloWorld.wellHelloThere thrpt 5 1402721640.465 ± 99207546.747 ops/s – 李建强 Jul 27 '20 at 06:09
  • Are you sure that you are not measuring how fast logging is now? Please either use a blackhole or simply `return` the result (where JMH will take care). – Johannes Kuhn Jul 27 '20 at 07:13
  • Thanks Johannes. I have changed the test to return the value and the logging go away.The performance result is very interesting as below: – 李建强 Jul 28 '20 at 02:44
  • Benchmark Mode Cnt Score Error Units JMHSample_01_HelloWorld.testFindVirtual thrpt 5 233366711.254 ± 21866604.586 ops/s JMHSample_01_HelloWorld.testReflectionGetIsEmpty thrpt 5 46304374.560 ± 5983090.448 ops/s JMHSample_01_HelloWorld.wellHelloThere thrpt 5 1430612460.532 ± 112317387.739 ops/s – 李建强 Jul 28 '20 at 02:51
  • Now the MethodHandle'way is even faster than the Java Reflection'way.Thank you,Johannes. – 李建强 Jul 28 '20 at 02:54
  • Does this answer your question? [How do I write a correct micro-benchmark in Java?](https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java) – Johannes Kuhn Dec 30 '20 at 23:10

0 Answers0