什么JVM优化导致这些性能结果?

时间:2014-07-25 16:58:56

标签: java performance jvm bytecode microbenchmark

执行Java REST服务性能测试我看到一个意外的模式:在每次调用中创建并返回相同值对象的方法比仅返回存储在类或对象字段中的值对象的另一个版本运行得更快。

代码:

@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; 
}

字节代码:

  • 内联(更快):getstatic,invokestatic,invokevirtual,areturn
  • 静态归档(较慢):getstatic,areturn
  • 对象字段(较慢):aload,getfield,areturn

性能(使用Apache AB,单线程,多次运行且结果一致):

  • 内联:17078.29 [#/ sec](卑鄙)
  • 静态字段:5242.64 [#/ sec](平均值)
  • 对象字段:5417.40 [#/ sec](平均值)

环境:RHEL6 + JDK Oracle 1.7.0_60-b19 64位

JVM是否有可能使用本机代码优化内联版本,但从未考虑优化其他两个,因为它们已经很小了?

1 个答案:

答案 0 :(得分:3)

正如评论中指出的那样,如果不实际查看装配,很难说清楚。由于yoy正在使用REST框架,我认为从组件中很难说,因为有很多代码需要阅读。

相反,我想给你一个有根据的猜测,因为你的代码是应用costant folding的典型例子。当内联值而不是从字段读取值时,JVM可以安全地假设该值是常量。当JIT编译该方法时,常量表达式因此可以安全地与您的框架代码合并,这可能会导致更少的JIT组合,从而提高性能。对于字段值,即使是final字段值,也不能假设常量值,因为字段值可以更改。 (只要字段值不是编译时常量,原语或常量String,由 javac 内联。)因此JVM可以可能不会不断折叠价值。

您可以在教程read more on constant foldingJMH注明:

  

如果JVM意识到计算的结果无论如何都是一样的,它可以巧妙地优化它。在我们的例子中,这意味着我们可以将计算移到内部JMH循环之外。这可以通过始终从状态读取输入,基于该状态计算结果,并遵循规则来防止DCE来防止。

我希望你使用这样的框架。否则,您的绩效指标不太可能有效。

通过阅读字节代码,您通常无法了解运行时性能,因为JIT编译器可以在优化期间将字节代码调整为任何内容。字节代码布局应该只在解释代码时才重要,这通常不是人们将性能测量为性能关键的状态, hot 代码总是进行JIT编译。