【问题标题】:why doesn't the java compiler rewrite this code?为什么java编译器不重写这段代码?
【发布时间】:2014-09-14 01:59:01
【问题描述】:

我正在使用此代码进行测试:

public class TestNull {
   public void leftComparison(String s) {
       if (s == null);
   }
   public void rightComparison(String s) {
       if (null == s);
   }
}

我用javac 1.8.0_05编译它,然后检查字节码:

public class TestNull {
  ....
  public void leftComparison(java.lang.String);
    Code:
       0: aload_1       
       1: ifnonnull     4
       4: return        

  public void rightComparison(java.lang.String);
     Code:
       0: aconst_null   
       1: aload_1       
       2: if_acmpne     5
       5: return        
}

显然,leftComparison 被编译为在堆栈上推送和弹出 1 个变量,而 rightComparison 推送和弹出 2。我推测 leftComparison 因此比 rightComparison 更有效?

我想知道为什么编译器不重写rightComparison的代码?在我看来,这两个比较在语义上应该是等价的,对吧?

【问题讨论】:

  • 如果编译器将您的代码重写为更简单但等效的代码,它根本不会生成字节码,因为这些方法什么都不做。 :-)
  • 因为没有ifnots字节码。 javac 翻译事物的方式非常直接。

标签: java compiler-construction compiler-optimization


【解决方案1】:

Java 字节码编译器在优化方面做的很少。严肃的优化工作几乎都是由JIT编译器完成的。

我想知道为什么编译器不重写rightComparison的代码?

因为重写它没有意义。 JIT 编译器应该能够同时处理这两个版本,并且很可能会为这两个版本生成最佳(本机)代码。 (有兴趣的可以看看这个,有办法看到JIT编译器生成的native code。)

(有关更多技术解释,请参阅@codenheim 的回答。)

在我看来,这两个比较在语义上应该是等价的吧?

没错……但这并不意味着字节码编译器有义务为两个版本生成相同的字节码序列。


这里真正的教训是,字节码编译器生成的字节码序列很少告诉你你的代码将如何实际执行。您可能通过读取字节码得出的任何性能结论都高度怀疑

【讨论】:

  • 很好的解释。谢谢。
【解决方案2】:

实际上,字节码相当于中间码。过早优化或优化两次的投资回报率较低。

  1. 它引入了不必要的维护开销层。
  2. 当我们知道目标平台时,最好进行优化。无论如何,基于 Java 堆栈的指令集并不适合高级优化。这太简单了(按设计)。我们只能通过改组一些基于堆栈的操作码来完成这么多的“优化”。虽然在 javac 中进行大量“不费吹灰之力”的优化是可行的,但我认为实用主义在这里获胜,我们将其投入到 JIT 中,它可以利用更丰富的本机指令集和技术(不同按平台)在字节码中不可用。

【讨论】:

    【解决方案3】:

    几乎是因为“它就是这样写的”。比较考虑左手变量并将其与右手变量进行比较。当您说null == s 时,您是在说“将null 与此变量进行比较”,因此代码定义了一个常量null 进行比较。编译器只是将另一个比较优化为非空检查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-06
      • 2013-08-08
      • 2011-11-27
      • 2010-10-24
      • 1970-01-01
      相关资源
      最近更新 更多