1. kawasima

    Posted

    kawasima
Changes in title
+Javaでfinalを付けると遅い?
Changes in tags
+Java
1.7
Changes in body
Source | HTML | Preview
@@ -0,0 +1,69 @@
+随分昔の記事を取り出して恐縮ですが、[finalをつけたらパフォーマンスが落ちたでござるの巻](http://d.hatena.ne.jp/shuji_w6e/20090821/1250868090) という話がありました。
+
+この違いがなぜ起こるか調べてみました。
+
+```java
+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オプションをつけて最適化して実行してみます。
+
+コードは以下のとおり。
+
+```java
+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を付けた方が、最適化されやすい」という通説どおりの結果になります。
+