编译器会识别并优化常用功能吗?

时间:2017-10-18 03:56:01

标签: java optimization compiler-optimization

我主要是针对Java,所以这就是这里的示例,但我希望这也适用于其他语言,如C或C ++。

第一种情况是针对常见功能。它是否会认识到代码做了某件事并用更优化的东西取而代之?

简单的例子:

int max(int a,int b){
    return a>b?a:b;
}

int rotateLeft(int a,int b){
    return (a<<b)|(a>>>-b);
}

boolean testBitLittleEndian(int v,int i){
    return (v>>i&1)!=0;
}

旋转不是那么明显,但为了解释,>>>是无符号/逻辑移位,并且移位量以宽度为模来解释。由于int是32位,因此仅使用移位量的最低有效5位。

我认为由JIT用原生旋转指令替换它。

不太明显的:

void intToByteLittleEndian(int v,byte[] b,int i){
    b[i+3]=(byte)(v>>24);
    b[i+2]=(byte)(v>>16);
    b[i+1]=(byte)(v>> 8);
    b[i  ]=(byte) v;
}

float median(float a,float b,float c){
    float d;//Swap
    if(a>b){d=a;a=b;b=d;}
    if(b>c){b=c;}
    return a>b?a:b;
}

甚至不接近最佳,但它简单易读。由于这些函数有很多变化,编译器可能很难正确地检测和优化它们。

同样,由于无法从Java获得优化版本所需的指令,因此可能由JIT进行替换。

特别是对于write int作为小端函数,为了防止编译器可能认为我们可以编写int的一部分然后得到一个越界异常,我们将先写入最后一个字节。

另一种情况是标准库函数,编译器可以确定这些函数应该做一些特定的事情。无需识别和替换代码,因此即使需要,也可以优化BigInteger中的数学等大函数。

Math类是在可能的情况下专门用快速原生指令替换的特殊类之一。

还有一些在低级语言中很简单,例如Double.doubleToLongBits()

int64_t doubleToLongBits(double v){
    return *(int64_t*)&v;
}

如果字节顺序错误,还有一些工作要做。

There are others with a pure Java implementation which will be optimized anyways

也可能只以这种方式优化 标准库函数,因为编译器很难准确知道代码的作用或其他原因。

我听说编译器无法进行此类优化的主要原因是他们无法确切地知道您想要什么,或者在这种情况下,您的代码所做的事情。除了一定的复杂性(不是很高)之外,编译器仍然无法以可以让它进行优化的方式分析您的代码。

1 个答案:

答案 0 :(得分:0)

这实际上是一堆问题。但...

javac没有优化,它不是它的工作。

JVM ......没有单一的JVM。有许多实现,它们通常在运行时进行优化。我们来谈谈amd64上的热点。

它识别一些模式和一些方法,google for&#34; JVM内在函数&#34;。

例如,Math.max使用条件移动进行优化,如果探查器这样说(很少采用条件分支的平均速度更快)。

Integer.rotateLeftLong.rotateRight等许多方法都针对单条指令进行了优化。你自己的代码没有。

按位操作有效实施。

你问题的其余部分听起来更像是答案......

通过这个blog,您可以了解很多有关热点优化的信息。