+= 在 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 次分叉。
背景
最近我发布了一个推荐类似内容的答案:
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 次分叉。