地平線に行く

2014-07-06

Java8 で java.lang.Object#hashCode() の生成アルゴリズムが変更されていました。

| 19:54 |

java.lang.Object#hashCode()の性質という記事で書いたのですが、Java の Object#hashCode() の値はただの乱数となっています。

この乱数アルゴリズムが、Java SE 8 で線形合同法」から「XORシフト方式」に変更になっていました。


といっても、変更されたのはたった1文字。

VMオプションデフォルト設定が -XX:hashCode=0 から -XX:hashCode=5 に変わっただけでした。

hotspot-rt Udiff hotspot/src/share/vm/runtime/globals.hpp


どういうこと?

もともと、Java の以前の実装*1 *2から、Object#hashCode() のアルゴリズムVMオプション -XX:hashCode=? で選べるようになっていました。

ですが、デフォルトは長いこと 0(=線形合同法による乱数) になっていました。

挙動
0線形合同法による乱数デフォルト
1オブジェクトのアドレス+乱数
2(常に)1
3連番
4オブジェクトのアドレス
その他XORシフト方式による乱数

しかし、Java SE 8 をリリースするにあたって改めて調べたところ、「-XX:hashCode=5(XORシフト方式)に変えたほうがマルチスレッドでのパフォーマンスが格段に良い*3」という結果が得られたそうです。

既存のプログラムに影響があるかもという慎重な意見もありましたが、影響があったら -XX:hashCode=0 を指定すればいいだけだということで、最終的に変更することになったようです(英語苦手なので、意味あってるか自信ないですが…)。

RFR (XS): CR 8006176: Switch to optimal identity hash code generator



ささやかな変更ながら、Java 8 でこういう細かいところまで手が加えられているのが分かって、ちょっと面白かったです。

*1:少なくとも OpenJDK の最初のコミットから存在していました。http://hg.openjdk.java.net/jdk6/jdk6/hotspot/annotate/a61af66fc99e/src/share/vm/runtime/synchronizer.cpp#l271

*2:この実装がされたとき、既にソースコードのコメントで「This is probably the best overall implementation -- we'll likely make this the default in future releases. (これはおそらく全体的に最良な実装です。我々はおそらく、将来のリリースでこれをデフォルトにします。)」という記載がされていました。

*3:該当のコードをざっと見た感じ、アルゴリズムの優秀さもありますが、乱数シードを各スレッドごとに独立して持っているというのもマルチスレッドでのパフォーマンス向上につながっているようです。

リンク元