+= 在 java 中的表现

Performance of += in java

背景

最近我发布了一个推荐类似内容的答案:

x = x + 2;

有人评论"Please use x += 2; instead."

在一定程度上研究了汇编语言和编译器之后,我一直认为这两个语句会简化为相同的汇编指令。因此,我也认为两者不会有性能上的差异,只是见仁见智而已。

收到上述评论后,我很好奇,并快速进行了 google 和 SO 搜索,结果一无所获。

我的问题

在java中x = x + 2;x += 2在性能上有区别吗?还是仅仅是可读性和风格的不同,让两者取舍见仁见智?

请提供证据,而非意见。

编译器以相同的方式执行这两个语句,执行时间或性能没有任何差异。 x+=2 被编译器解释为 x = x+2 并且在执行时间上应该没有差异。

我认为唯一的区别是可读性。在 class 研究这个时,我们被告知 x += 2 实际上不太常见。

this 问题的答案似乎表明它取决于您使用的编译器,接受的答案说对于大多数编译器它是相同的。

This other 问题特定于 Java,并提供了更多证据。

下面是 Eclipse 编译器所做的(见下面的编辑)。

Java代码:

public static void x( int x)
{
    x = x + 2;
}

字节码:

public static void x(int);
  Code:
     0: iinc          0, 2
     3: return

Java代码:

public static void x( int x)
{
    x += 2;
}

字节码:

public static void x(int);
  Code:
     0: iinc          0, 2
     3: return

如您所见,它们编译成相同的字节码。 Java 编译器会大量优化您的代码,所以不要试图为琐碎的事情优化它,尤其是要以牺牲可读性为代价。

编辑:事实证明并非所有编译器都将这些语句编译为相同的字节码。然而,原点仍然成立。不要试图为琐碎的事情优化 Java 代码,尤其是要以牺牲可读性为代价;因为 JIT 编译器 在将字节码编译成本机代码时会大量优化您的代码,即使某些 Java 编译器会跳过一些优化。

为这两段代码生成的字节码在我的机器上是不同的(很可能在你的机器上),但这并不重要。首先,优化后 JVM 的机器码实际上 运行 可能是相同的;其次,实际上您不会注意到任何差异。尝试自己对其进行基准测试(这个 PDF presentation 解释了为什么你不应该这样做),比如说,在一个循环中,你会发现你得到的各种结果在 运行 之间可能相差 n 倍and/or 经过细微的改动,这发生在您尽可能可预测的环境中。想象一下在真实代码中会发生什么,其中任何一行都不可能是实质性的 CPU-spender.

运行为此代码设置了一个适当的 JMH 微基准测试表明,在这两种变体中,它 运行s 在 ~3-4 纳秒内(连同从字段加载初始值并从该方法返回结果,否则整个方法可能会被丢弃)。我有点怀疑某些框架能否在我的桌面上以如此精确的方式测量时间,但我认为要么这是真的,要么这两段代码的实际时间被其他成本淹没了(调用方法?加载)一个值?返回一个值?)。

Benchmark        Mode  Cnt       Score      Error   Units
MyBenchmark.f1  thrpt   30  281747,576 ± 9748,881  ops/ms
MyBenchmark.f2  thrpt   30  289411,317 ± 8951,254  ops/ms

为了完整起见,我使用的基准是

import org.openjdk.jmh.annotations.*;
import java.util.concurrent.*;

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class MyBenchmark {

    public int a = 0xDEADBEAF;

    @Benchmark
    public int f1() {
      int x = a;
      x += 2;
      return x;
    }

    @Benchmark
    public int f2() {
      int x = a;
      x = x + 2;
      return x;
    }
}

运行 10 次预热迭代,10 次测量迭代,3 次分叉。