Java Compiler是否会优化简单的重复数学运算,如:
if (prevX / width != curX / width) {
// Do something with prevX / width value
} else {
// Do something with curX / width value
}
我知道我可以在if语句之前将结果分配给变量,并返回变量,但这有点麻烦。如果编译器自动识别出正在进行相同的计算并将结果缓存到临时变量中,我宁愿坚持上述约定。
*编辑 - 我是个白痴。我试图简单地/抽象地提出我的问题。它不是简单的:if(x> y)
答案 0 :(得分:7)
答案是肯定的。这称为Common Subexpression Elimination,是Java,C / C ++等中使用的标准(强大)编译器优化...
This page确认HotSpot JVM将进行此优化。
那就是说,编译器/运行时是否能够在你期望的时候进行这种优化是另一回事。所以我通常更喜欢自己做这些优化,如果它也增强了可读性。
double xw = x / width;
double yw = y / width;
if (xw > yw) {
return xw;
} else {
return yw;
}
答案 1 :(得分:3)
编译器可以执行此类优化。它是否确实取决于以下答案:
编译器是否允许通过JLS执行此操作?
在某些情况下不是。例如,如果prevX
是volatile
实例变量,那么每次源代码说它都被使用时,它必须从内存中获取。另一种情况是公共子表达式涉及具有可观察副作用的方法调用;即程序中的其他内容可能能够判断方法是否被调用一次或两次。
编译器能够执行此操作吗?
编译器需要分析代码以检测可以合法优化的常见子表达式。这里有两个问题:
编译器是否能够执行必要的推理?例如,可以假设编译器可以确定特定方法调用将是无副作用的,因此可以进行优化。但是,构建一个实际上能够执行此操作的编译器是......并且有趣的问题。
优化是否值得?在执行优化的成本与收益之间存在权衡。这不是一个直接的权衡。它需要考虑查看是否可以执行优化的成本......当它实际上不能执行时。换句话说,对编译时间的影响。 (请记住,在Java中,优化主要是在运行时由JIT编译器完成的......因此这会影响应用程序性能。)
在一个像你这样的简单示例中,优化是合法的(模volatile
),并且应该期望一个半合适的JIT编译器来执行它。
另一个问题是你是否应该通过明确地评估代码的常用表达式并将结果分配给临时代表来尝试帮助编译器。
IMO,答案通常是否定的。
一个好的编译器可能会像你一样做得好。如果没有,那么下一代可能会这样做。
代码可能不保证手动优化。除非您已经分析了代码以确定瓶颈的位置,否则您的手部优化很可能与实际应用程序性能无关 ...并且浪费您的时间。
< / LI>你有可能把它填满;例如通过忘记方法调用具有重要的副作用,或者变量是volatile
,这是有充分理由的。
另一方面,如果重写使您的代码更具可读性,那么这是一个很好的理由。
答案 2 :(得分:2)
通常,“是” - 如果可以,编译器将优化代码,HotSpot JVM也可以改进重复执行的代码块。
但是,在这种情况下,最好像这样重构代码:
if (x > y)
return x / width;
return y / width;
,如果x > y
,则可以避免一次除法操作。