java - 如何正确使用JMH? ArrayList 示例

标签 java performance jmh

在我的示例中,理论上 2 种方法的性能应该非常相似。在第一种情况下,我使用数组,在第二种情况下 - ArrayList 具有保证的容量。
结果如下:

LessonBenchmark2.capacityTestArray avgt 5 1,354 ± 0,057 ms/op


LessonBenchmark2.capacityTestArrayListEnsured avgt 5 32,018 ± 81,911 ms/op


这里似乎数组要快得多(1.354 vs 32.018 ms/op)。可能是我的 JMH 基准测试设置不正确。如何做对?
此外,如果我使用 @Setup(Level.Invocation),那么结果很接近(1,405 对 1,496 ms/op):

LessonBenchmark.capacityTestArray avgt 5 1,405 ± 0,143 ms/op

LessonBenchmark.capacityTestArrayListEnsured avgt 5 1,496 ± 0,104 ms/op


但是据说要小心使用 Invocation 。此外,迭代模式在逻辑上似乎是正确的。
这是代码:
public static void main(String[] args) throws Exception {
    org.openjdk.jmh.Main.main(args);
}

static final int iter = 5;
static final int fork = 1;
static final int warmIter = 5;

@State(Scope.Benchmark)
public static class Params {
    public int length = 100_000;
    public Person[] people;
    public ArrayList<Person> peopleArrayListEnsure;

    // before each iteration of the benchmark
    @Setup(Level.Iteration)
    public void setup() {
        people = new Person[length];
        peopleArrayListEnsure = new ArrayList<>(length);
    }
}

@Benchmark
@Warmup(iterations = warmIter)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = fork)
@Measurement(iterations = iter)
public void capacityTestArray(Params p) {
    for (int i = 0; i < p.length; i++) {
        p.people[i] = new Person(i, new Address(i, i), new Pet(i, i));
    }
}

@Benchmark
@Warmup(iterations = warmIter)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = fork)
@Measurement(iterations = iter)
public void capacityTestArrayListEnsured(Params p) {
    for (int i = 0; i < p.length; i++) {
        p.peopleArrayListEnsure.add(new Person(i, new Address(i, i), new Pet(i, i)));
    }
}

public static class Person {
    private int id;
    private Address address;
    private Pet pet;

    public Person(int id, Address address, Pet pet) {
        this.id = id;
        this.address = address;
        this.pet = pet;
    }
}

public static class Address {
    private int countryId;
    private int cityId;

    public Address(int countryId, int cityId) {
        this.countryId = countryId;
        this.cityId = cityId;
    }
}

public static class Pet {
    private int age;
    private int typeId;

    public Pet(int age, int typeId) {
        this.age = age;
        this.typeId = typeId;
    }
}

最佳答案

测试设计不当;在你的测试中,因为 arraylist 只为多次调用创建一次,基于数组的代码只是多次覆盖同一个数组,而 arraylist 版本添加的越来越多,需要增长。
一个微不足道的解决方法是先清除它。另一个解决方法是在此处停止使用状态,而将对象的创建(无论是 100k 人数组,还是预定义为 100k 人的人员数组列表)作为测试工具的一部分。一旦你解决了这个问题,考虑到错误,结果是完全相同的,对于此 ,数组和数组列表之间的性能完全没有区别。 .

MyBenchmark.capacityTestArray             avgt    5  1,325 ± 0,059  ms/op
MyBenchmark.capacityTestArrayListEnsured  avgt    5  1,287 ± 0,157  ms/op
我通过删除 Params 来简化完全声明,并在每个测试的支出中创建列表和数组部分:
    static final int LEN = 100_000;
    
    public void capacityTestArray() {
        Person[] people = new Person[LEN];
        for (int i = 0; i < LEN; i++) {
            people[i] = new Person(i, new Address(i, i), new Pet(i, i));
        }
    }

    public void capacityTestArrayListEnsured() {
        List<Person> p = new ArrayList<Person>(LEN);
        for (int i = 0; i < LEN; i++) {
            p.add(new Person(i, new Address(i, i), new Pet(i, i)));
        }
    }
(保持所有注释和 PersonAddress 等类相同)。
或者,使用您现有的代码,然后扔一个 list.clear()在顶部。

关于java - 如何正确使用JMH? ArrayList 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66243067/

相关文章:

java - 我如何要求用户在第一次启动时选择一个设置?

java - 带有请求参数和内容正文的 Web 请求

java - 覆盖jar中的java类

.net-3.5 - .Net 静态方法及其对并发的影响?

mysql - SQLite:创建多个索引、多个索引列与单个索引哪一个将有助于获得最佳性能?

java - 如何用jmh写一个getbytes的小基准测试?

java - jdk-9/jdk-8 和 jmh 中的新实例与新实例

java - 写hadoop的java api需要SSH吗?

C# NAudio 获取音频文件持续时间/性能

java - JMH AnnotationProcessor NullPointerException