Java 为什么JMH对不同的实现显示相同的结果?

Java 为什么JMH对不同的实现显示相同的结果?,java,jvm,jmh,Java,Jvm,Jmh,JMH为不同的方法显示相同的结果,无论这些方法是否包含任何代码 示例1:要测试的空方法 public class MyBenchmark { public static void main(String[] args) throws Exception { org.openjdk.jmh.Main.main(args); } @Fork(value = 1, warmups = 0) @Benchmark @BenchmarkMode(M

JMH为不同的方法显示相同的结果,无论这些方法是否包含任何代码

示例1:要测试的空方法

public class MyBenchmark {
    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }

    @Fork(value = 1, warmups = 0)
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 5)
    public String run() {
        return "done";
    }
}
运行此代码的结果是1e-8 s/op

示例2:有一些工作要做的方法:

public class MyBenchmark {
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 10000000; i++) {
            list.add(i);
        }
        org.openjdk.jmh.Main.main(args);
    }

    private static List<Integer> list = new ArrayList<>();

    @Fork(value = 1, warmups = 0)
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 5)
    public String run() {
        List<Integer> copy = new ArrayList<>();
        for (Integer item : list) {
            copy.add(item);
        }
        return "done";
    }
}
公共类MyBenchmark{
公共静态void main(字符串[]args)引发异常{
对于(int i=0;i<10000000;i++){
列表.添加(i);
}
org.openjdk.jmh.Main.Main(args);
}
私有静态列表=新的ArrayList();
@叉子(值=1,预热=0)
@基准
@基准模式(模式平均时间)
@预热(迭代次数=5次)
公共字符串run(){
列表副本=新建ArrayList();
用于(整数项:列表){
副本。添加(项目);
}
返回“完成”;
}
}
结果是一样的:1e-8 s/op


因此,基准显然不起作用。可能有什么问题?

您使用的时间刻度不正确-每次操作秒数。对于你的无操作测试来说,它似乎太大了。只需将以下参数
@OutputTimeUnit(TimeUnit.NANOSECONDS)
添加到测试中:

import org.openjdk.jmh.annotations.*;

import java.util.concurrent.TimeUnit;

public class MyBenchmark {
    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }

    @Fork(value = 1, warmups = 0)
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 5)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public String run() {
        return "done";
    }
}
结果如下:

# Run complete. Total time: 00:00:25

Benchmark        Mode  Cnt  Score   Error  Units
MyBenchmark.run  avgt   20  5.390 ± 0.264  ns/op
关于第二个示例,它包含几乎所有可能的问题/陷阱:

  • 死代码elimintaion-JVM足够智能,可以检测循环而不会产生副作用,并将其从方法体中删除
  • 测量错误
  • 不正确的初始化-JMH具有特殊注释
    设置
    状态
    ,用于正确的基准初始化
以下是您的示例的“正确”版本(我刚刚删除了不经意的错误):


为了了解微基准标记的所有可能问题,请阅读。

您使用的时间刻度不正确-每次操作秒数。对于你的无操作测试来说,它似乎太大了。只需将以下参数
@OutputTimeUnit(TimeUnit.NANOSECONDS)
添加到测试中:

import org.openjdk.jmh.annotations.*;

import java.util.concurrent.TimeUnit;

public class MyBenchmark {
    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }

    @Fork(value = 1, warmups = 0)
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 5)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public String run() {
        return "done";
    }
}
结果如下:

# Run complete. Total time: 00:00:25

Benchmark        Mode  Cnt  Score   Error  Units
MyBenchmark.run  avgt   20  5.390 ± 0.264  ns/op
关于第二个示例,它包含几乎所有可能的问题/陷阱:

  • 死代码elimintaion-JVM足够智能,可以检测循环而不会产生副作用,并将其从方法体中删除
  • 测量错误
  • 不正确的初始化-JMH具有特殊注释
    设置
    状态
    ,用于正确的基准初始化
以下是您的示例的“正确”版本(我刚刚删除了不经意的错误):


为了了解微基准标记的所有可能问题,请阅读。

当您将任何实际工作放在该方法中时,会有什么不同吗?使其无法工作。在我的例子中,空方法的工作时间甚至比“重”方法更长……当你在这个方法中放入任何实际工作时,会有什么不同吗?使其无法工作。在我的例子中,空方法的工作时间甚至比“重”方法更长。。。