1. kawasima

    Posted

    kawasima
Changes in title
+Javaでfinalを付けると遅い?
Changes in tags
+Java
1.7
Changes in body
Source | HTML | Preview

随分昔の記事を取り出して恐縮ですが、finalをつけたらパフォーマンスが落ちたでござるの巻 という話がありました。

この違いがなぜ起こるか調べてみました。

public static void main(String[] args) {
    final int NUM = 31;
    long start = System.currentTimeMillis();
    for (int i = 0; i < Integer.MAX_VALUE; i++) {
        int hash = 17;
        hash = hash * NUM + i;
        hash = hash * NUM + i;
        hash = hash * NUM + i;
        hash = hash * NUM + i;
        hash = hash * NUM + i;
    }
    System.out.println(System.currentTimeMillis() - start);
}

この場合、javapの結果を眺めてみると、違いはが出てくるのは、finalを付けるとスタックに積むのがbipush命令になり、finalを付けないとiload_1命令になるという点だけです。

これをWindowsで実行すると…

finalあり:3244
finalなし:2527

確かにfinalなしの方が速い結果が得られます。

しかしこのコードよく見ると、hashがループの外で使われていないので、最適化のやり方次第で大きく差がでてしまいます。-XintをつけてJITを効かせずに実行してみます。

finalあり:57513
finalなし:57441

変わりません。つまりbipushとiload_1で速度差は無いということです。

さて比較をフェアにするために、hashをループの外で使うようにして、-serverオプションをつけて最適化して実行してみます。

コードは以下のとおり。

public static void main(String[] args) {
    final int NUM = 31;
    long start = System.currentTimeMillis();
    int hash = 17;
    for (int i = 0; i < Integer.MAX_VALUE; i++) {
        hash = hash * NUM + i;
        hash = hash * NUM + i;
        hash = hash * NUM + i;
        hash = hash * NUM + i;
        hash = hash * NUM + i;
    }
    System.out.println(hash +":"+ (System.currentTimeMillis() - start));
}

結果は…

finalあり:9021
finalなし:12478

となり、「finalを付けた方が、最適化されやすい」という通説どおりの結果になります。