What JVM optimization causes these results?

Running a Java REST service performance test I see an unexpected pattern: a method that always creates and returns the same value object in every call is faster than the other version, which simply returns the value object stored in the class or object field.

The code:

@POST @Path("inline") public Response inline(String s) { return Response.status(Status.CREATED).build(); } private static final Response RESP = Response.status(Status.CREATED).build(); @POST @Path("staticfield") public Response static(String s) { return RESP; } private final Response resp = Response.status(Status.CREATED).build(); @POST @Path("field") public Response field(String s) { return resp; } 

Bytecode:

  • Inline (faster): getstatic, invokestatic, invokevirtual, areturn
  • Static feed (slower): getstatic, areturn
  • Object field (slower): aload, getfield, areturn

Performance (using Apache AB, single thread, multiple starts with consistent results):

  • Inline: 17078.29 [# / sec] (average)
  • Static field: 5242.64 [# / sec] (average)
  • Object field: 5417.40 [# / sec] (average value)

Environment : RHEL6 + JDK Oracle 1.7.0_60-b19 64 bit

Is it possible that the JVM optimized the embedded version using native code, but never considered optimizing the other two, because they are already quite small?

+7
java performance jvm bytecode microbenchmark
source share
1 answer

As stated in the comments, it’s hard to say without looking at the assembly. Since yoy uses the REST-framework, I assume that it will be difficult to say from the assembly, since there is a lot of code to read.

Instead, I want to give you a reasonable assumption, because your code is an archetypal example of costant folding . When a value is specified and not read from a field, the JVM can safely assume that this value is constant. When the method is JIT-compiled, the constant expression can be safely combined with your framework code, which probably leads to a smaller increase in JIT and, consequently, to increased performance. For a field value, even a final one, a constant value cannot be taken as changing a field value. (As long as the field value is not a compile-time constant, the primitive or String constant is enclosed in javac.) Thus, the JVM may probably not reset the constant value.

You can read more about the permanent crease in the JMH tutorial, which notes:

If the JVM implements the result of the calculation, then the same thing, no matter what, it can intelligently optimize it. In our case, this means that we can move the calculation outside the internal JMH loop. This can be prevented by always reading the inputs from the state, calculating the result based on that state, and following the rules to prevent DCE.

I hope you used such a structure. Otherwise, the performance metric is unlikely to be valid.

From reading byte code, you usually can't learn much about performance at runtime, as the JIT compiler can tune the byte code for something during optimization. The layout of the byte code should only matter when interpreting code, which is usually not a state in which you could evaluate performance as critical to performance, and the hot code has always been JIT.

+3
source share

All Articles