【问题标题】:Java null check performanceJava空值检查性能
【发布时间】:2018-06-08 06:58:14
【问题描述】:

我想知道在 java 中通过直接比较或使用 Objects.isNull() 方法检查对象是否为 null 是否有任何显着差异。

public class Test {

  public final static Long ITERATIONS = 100000000L; 

  @Test
  public void noFnCalls() {
    balong startTime = System.currentTimeMillis();
    Object x = new Object();
    Long i;
    for (i = 0L; i < ITERATIONS; i++) {
      boolean t = x == null;
    }
    long estimatedTime = System.currentTimeMillis() - startTime;
    System.out.println("noFnCalls ellapsed time: " + estimatedTime);
  }

  @Test
  public void withFnCalls() {
    long startTime = System.currentTimeMillis();
    Object x = new Object();
    Long i;
    for (i = 0L; i < ITERATIONS; i++) {
      boolean t = Objects.isNull(x);
    }
    long estimatedTime = System.currentTimeMillis() - startTime;
    System.out.println("withFnCalls ellapsed time: " + estimatedTime);
  }
}

令人惊讶的是,至少对我来说,完成“noFnCalls”总是需要更多时间。我期待的结果几乎相反,因为它会导致使用堆栈的方法调用。

这是输出:(显然,每次都会更改,但总是“noFnCalls”更高)

noFnCalls 已用时间:583

withFnCalls 耗时:463

为什么会这样?

【问题讨论】:

  • 在 Java 中编写正确的微基准测试非常棘手。你有没有预热你的系统?如果您以相反的顺序运行测试,您的结果是否相同?
  • 实际上,使用两者中的哪一个并不重要,因为性能增益是最小的。但是,Objects#isNull 旨在用作谓词。
  • 此测试无效,t 未使用且不变。

标签: java performance performance-testing


【解决方案1】:

您看到的结果可能是由于首先运行“noFnCalls”,而没有在测试和测量之前引入适当的预热。

我明白了:

withFnCalls ellapsed time: 444
noFnCalls ellapsed time: 471
withFnCalls ellapsed time: 334
noFnCalls ellapsed time: 331
withFnCalls ellapsed time: 330
noFnCalls ellapsed time: 325
withFnCalls ellapsed time: 331
noFnCalls ellapsed time: 326
withFnCalls ellapsed time: 326
noFnCalls ellapsed time: 328

使用

import java.util.Objects;

public class Test {

  public final static Long ITERATIONS = 100000000L; 

  public static void main(String args[]) {
    withFnCalls();
    noFnCalls();
    withFnCalls();
    noFnCalls();
    withFnCalls();
    noFnCalls();
    withFnCalls();
    noFnCalls();
    withFnCalls();
    noFnCalls();
  }
  public static void noFnCalls() {
    long startTime = System.currentTimeMillis();
    Object x = new Object();
    Long i;
    for (i = 0L; i < ITERATIONS; i++) {
      boolean t = x == null;
    }
    long estimatedTime = System.currentTimeMillis() - startTime;
    System.out.println("noFnCalls ellapsed time: " + estimatedTime);
  }

  public static void withFnCalls() {
    long startTime = System.currentTimeMillis();
    Object x = new Object();
    Long i;
    for (i = 0L; i < ITERATIONS; i++) {
      boolean t = Objects.isNull(x);
    }
    long estimatedTime = System.currentTimeMillis() - startTime;
    System.out.println("withFnCalls ellapsed time: " + estimatedTime);
  }
}

withFnCalls ellapsed time: 3618
noFnCalls ellapsed time: 3361
withFnCalls ellapsed time: 3445
noFnCalls ellapsed time: 3278
withFnCalls ellapsed time: 3350
noFnCalls ellapsed time: 3292
withFnCalls ellapsed time: 3309
noFnCalls ellapsed time: 3262
withFnCalls ellapsed time: 3293
noFnCalls ellapsed time: 3261

如果我增加到 1000000000L 次迭代。这是使用 Java 9 64 位服务器 jvm,构建 9+181,由 Oracle 完成的,在 Windows 10 上运行,机器具有 Intel i5-2600 cpu。

正如其他人所说,微基准测试是困难,许多不同的事情会影响结果。你不应该通过这样的测试得出结论。这种测试并不能说明太多 - 任何差异都很容易在彼此如此接近的噪声测量代码中丢失。

关于 java 中的微基准测试的必修推荐线程:How do I write a correct micro-benchmark in Java?

【讨论】:

  • 在 Windows 10、Linux/Debian 和 FreeBSD 上使用 Java 1.8.0 x64 的结果也相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 2018-07-04
  • 1970-01-01
  • 2018-01-18
  • 1970-01-01
相关资源
最近更新 更多