【问题标题】:Declaring booleans Optimization声明布尔优化
【发布时间】:2014-12-18 17:03:49
【问题描述】:

java编译器会优化这个吗:

boolean foo1 = getSomeHardToGetBoolean();
boolean foo2 = getSomeEasyToGetBoolean();
if(foo1 && foo2){
//do stuff
}

到这里:

if(getSomeEasyToGetBoolean() && getSomeHardToGetBoolean()){
//do stuff
}

甚至这个:

if(getSomeHardToGetBoolean() && getSomeEasyToGetBoolean()){
//do stuff
}

我将第一种方法用作可读性的一般做法,但代价是什么?

旁注:假定为 Java 8。使用 JIT。直到运行时才能确定布尔值。布尔值彼此完全独立。我可能不会停止使用第一种方式,但我只是好奇。谢谢!

【问题讨论】:

  • 如果您不每秒执行数千次,性能成本可以忽略不计。过早的优化是万恶之源。
  • 您指的是哪个编译器(javac 还是 JIT)? foo1 和 foo2 是否是“常数”,即使它们不是 JLS 的正式常数?您能否详细说明其中的内容?为什么不期望它一直优化到if (false),然后删除死代码?如果您担心性能,请注意即使优化器不处理它,这对于分支预测器来说也很容易。
  • 写微基准。运行百万次后,您将看到它是否得到了优化。
  • 一个好的优化器会将if (foo1 && foo2);优化为一个空语句,因为无论条件是真还是假,你的代码都不会做任何事情。另一方面,如果您在if 之后有一个实际语句或块而不是分号,这是一个更有趣的问题。
  • @Evorlor 也许吧。理论上,编译器可以跟踪方法可能产生的副作用。在实践中,如果您希望您的程序在一年内完成编译,那么优化器可以做的事情是有限度的。如果getSomeEasyToGetBoolean 足够简单,那是可能的。但是确定任何特定编译器的唯一方法是尝试它。语言本身并没有指定这些内容。

标签: java compiler-optimization


【解决方案1】:

优化器必须维护程序的语义。所以,如果 getSomeEasyToGetBoolean() 和 getSomeHardToGetBoolean() 有可观察到的副作用,优化器就不能忽略这些副作用,因为这会改变程序的语义。

但是,如果这些操作没有可观察到的副作用,优化器确实会执行诸如内联、重新排序和将条件移动到代码块开头的转换,这些都属于优化器的标准库。

这就是为什么多线程程序在没有适当同步结构的情况下访问公共数据结构可能会严重崩溃的原因,因为在这种情况下,线程可能会观察到执行优化代码的线程的行为发生变化。

【讨论】:

  • 在我有限的知识中,这个答案和 Ibalazscs 答案/cmets 似乎相互矛盾。你能解释一下这两个答案是如何相遇的吗?
  • 我认为这两种方法足够复杂,以至于编译器无法确定它们没有副作用。
  • lbalazscs 的回答是正确的,即如果调用的方法有副作用,则不允许进行此类优化。 (因此你永远不能编写程序来测试这种优化是否发生)但是它并没有考虑到 HotSpot 使用 aggressive inlining 可以检测是否有这样的副作用。
【解决方案2】:

考虑到getSomeEasyToGetBoolean() 和getSomeHardToGetBoolean() 可能有副作用,所有三个sn-ps 的代码都有不同的功能,如果编译器混合它们会出错

【讨论】:

  • 好点。第三种方式不同。但我认为前两个应该完全一样
  • @Evorlor 不。第一个总是运行这两种方法,第二个有时只运行getSomeEasyToGetBoolean() 方法。
  • @Slanec 啊我现在很困惑。所以编译器不会从第一种方式优化到后两种方式之一?
  • @Evorlor 如果第一个操作数的计算结果为假,则 && 运算符停止计算,因为结果将为假
  • 正如 Holger 所说,如果 JIT 能够证明方法没有副作用,它可能会内联它们的代码并将其优化为您想要的形式。大概吧。
【解决方案3】:

简而言之,没有。

考虑到if 语句可能嵌套在循环中,并且布尔值可能在运行时(编译后,即使使用 JIT)

【讨论】:

    猜你喜欢
    • 2013-02-01
    • 1970-01-01
    • 2015-01-11
    • 2014-08-22
    • 2015-05-23
    • 2017-02-11
    • 2014-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多