java - 两种相同方法的性能差异

标签 java performance jmh

我正在阅读 JMH 框架的示例,我对名为 JMHSample_12_Forking 的示例中的代码有疑问.运行此代码后,我得到以下结果(正如作者预测的那样):

testJavaUtilConcurrency.JMHSample_12_Forking.measure_1_c1         avgt    5   3.314 ±  0.200  ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_2_c2         avgt    5  22.403 ±  1.023  ns/op
...

这个结果解释如下:

Note that C1 is faster, C2 is slower, but the C1 is slow again! This is because ...

但我的问题是:为什么 C2 比 C1 慢?两个类和两个方法中的代码看起来完全一样,那么,性能差异的根源是什么?

更新:

我尝试为 Counter 添加第三个实现并获得以下结果:

testJavaUtilConcurrency.JMHSample_12_Forking.measure_1_c1         avgt    5   3.328 ± 0.073  ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_2_c2         avgt    5   22.437 ± 0.552  ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_2_c3         avgt    5  44.614 ± 5.080  ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_3_c1_again   avgt    5  43.535 ± 1.154  ns/op

最佳答案

在第一个测试中,有一个 Counter 的实现。 JIT 编译器能够假定任何调用 measure(Counter) 的东西都使用相同的实现,因此它可以内联来自 inc() 的代码。

在第二个测试中,我们引入了第二个实现 - 现在调用需要内联两个实现,或者在每次迭代时执行动态调度。由于不确定性(无论选择哪种),这比第一次测试慢得多。

在第三个测试中,我们使用与第一个测试相同的实现 - 但世界状态与第一个测试不同,因为 JIT 仍然知道第二个实现存在......它不能'不要回过头来相信只有一个 Counter 的实现...所以它仍然必须以比第一个测试更慢的方式执行 inc()

这个故事的寓意是,影响性能的不仅仅是代码,还有世界的状态。第一次测试中的世界状态(从优化的角度来看)比第二次和第三次测试中的世界状态要好得多。

关于java - 两种相同方法的性能差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33658953/

相关文章:

java - 打印浮点值

java - 如何使用dom4j在java中的另一个xml文档中插入一个xml节点作为第一个子节点?

java - 如何在 JTree 中的节点旁边显示特定的属性名称和值?

vba - 性能优化

c# - 查询嵌套递归对象的性能问题

c++ - 了解 std::string 的效率

java - 为什么 Java 使用包含 X 的外部变量的函数比直接使用 X 更快?

Java:对外部构造对象的依赖注入(inject)?

java - JMH 中的不对称基准

java - JMH 基准迭代中的随机峰