【问题标题】:Analysis of various incremental operators vs assignment and incrementing分析各种增量运算符 vs 赋值和自增
【发布时间】:2023-04-11 00:12:01
【问题描述】:

所以不久前有人问Is the ++ operator more efficient than a=a+1?。我以为我之前分析过这个,最初说a = a + 1和增量运算符++没有区别。事实证明,a++++aa += 1 都编译为相同的字节码,但 a = a + 1不是,如下所示:

public class SO_Test
{
    public static void main(String[] args)
    {
        int a = 1;
        a++;
        a += 1;
        ++a;    
    }
}

输出:

例子:

public class SO_Test
{
    public static void main(String[] args)
    {
        int a = 1;
        a = a + 1;
        a++;
        a += 1;
        ++a;    
    }
}

输出:

简而言之,a = a + 1 发出 iload_1iconst_1iaddistore_1,而其他只使用 iinc

我试图合理化这一点,但我无法做到。在这种情况下,编译器是否智能不足以优化字节码?这些是不同的有充分的理由吗?这是由 JIT 处理的吗?除非我解释不正确,否则我似乎永远不应该使用a = a + 1,我认为这肯定只是一种风格选择。

【问题讨论】:

  • 我觉得这里有两个方面1)编译时优化2)运行时优化。您现在观察到的与编译时优化有关。我认为我们需要在运行时优化之后决定应该/不应该使用。
  • 这真的不是对字节码差异的全面分析;您所展示的只是字节码对于独立表达式语句是相同的。当您实际使用a++++a 的结果 时会发生什么?编写了一个必须识别各种前/后增量模式的反编译器后,我记得存在更细微的差异。当然,实例字段、静态字段和数组元素的结果也往往不同。
  • @MikeStrobel 是的,我绝对应该说详细的分析——实际上恰恰相反。不幸的是,目前我没有多少时间做任何详细的事情。或许是在休息...
  • 看看我的Procyon反编译器;它可能会加快你的实验。编写一些测试,在不同的上下文中使用每种增量样式并比较反编译的结果。如果反编译器为所有三个上下文选择相同的运算符,则字节码可能是相同的。如果它重构了原始运算符,则可能存在差异。隔离这些情况,然后分析字节码(使用 -r 运行 Procyon 以获取原始字节码)。
  • @MikeStrobel 谢谢,我去看看。

标签: java bytecode


【解决方案1】:

流行的理念是javac 故意选择不优化生成的代码,依靠 JIT 编译器在运行时进行优化。后者对执行环境(硬件架构等)以及代码在运行时的使用方式有更好的信息。

如今,我认为您无法仅通过读取字节码就性能得出任何现实的结论。抛开关于过早优化的争论,如果你真的想知道是否有区别,construct a micro-benchmark 自己看看。

【讨论】:

    【解决方案2】:

    值得注意的是,这是特定于编译器的。我发现至少有一个 Eclipse 版本以与 x++ 相同的方式编译 x=x+1。此外,这仅与局部变量有关,因为字段没有类似的字节码指令。它仅适用于int 类型的变量。所以字节码的影响是相当有限的。它最有可能改进常见的for(int i=start; i<limit; i++) 模式。在语言方面,特别是对于 a[b()] ++a[b()] = a[b()] + 1 等而言,它会有所不同。

    【讨论】:

      猜你喜欢
      • 2014-08-25
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2023-03-08
      • 2016-02-02
      相关资源
      最近更新 更多