Quitada ブログ HAX

Hatena Blog でも Quitada ブログ

UseCompressedOops オプションのデフォルト値

Java SE 6 な JVMOracle 実装(いわゆる元 Sun の Hotspot VM)Update 14 のタイミングで、64 ビット版で UseCompressedOops というオプションが使えるようになりました。本オプションの技術的概要については、下記サイトとか参照してください。

UseCompressedOops - Hotspot JVMの圧縮OOP

ものすごく単純に言ったバージョンは、Update 14 のリリースノート参照。
http://java.sun.com/javase/ja/6/webnotes/6u14.html

-XX:+UseCompressedOops オプションを使用すると、Java オブジェクトヒープのサイズが 32 ギガバイト未満の場合に、64 ビット JRE のパフォーマンスを向上させることができます。この場合、HotSpot はオブジェクト参照を 32 ビットに圧縮して、処理する必要のあるデータの量を減らします。

64 ビットなアドレス空間だと、論理的には 16 エクサバイト(バイナリワールドでは、エクサはテラの 1,048,576 倍)のメモリ空間を扱えるくらい広大。「ビッグデータ」がバズワード化している昨今においても、一つのシステムでそんなに使わない。むしろ、Java の場合は無駄にオブジェクトポインタ用に使用する管理領域のメモリ使用量が 32 ビットのそれに比べてとても増えてしまう。なんで、オブジェクトポインタだけを 32 ビットにして、その分、指定可能な最大の java ヒープサイズを 32 ギガバイトに抑えて(現実的に考えて十分なサイズ)、オブジェクトポインタのメモリフットプリントを削減して効率的にメモリを使用しましょう、というオプションだと理解。

それでもって、興味本位でこのオプションのデフォルト値を調べてみた。そのためには以下のオプションが便利。

-XX:+PrintFlagsFinal

これをつけると、使用可能な JVM オプション一覧と現在の値を表示してくれるのです。なので、他のオプション何もつけずにこれだけつけて java コマンドを実行すればデフォルト値がわかるというわけ(PrintFlagsFinal のデフォルト値を除く)。で、以下の感じで、UseCompressedOops のデフォルトを調べてみた。

java -XX:+PrintFlagsFinal | grep UseCompressedOops

結果は、true でした。つまり、UseCompressedOops はデフォルトで有効で、64 ビット JVM でも最大 java ヒープサイズは 32GB に抑えられているわけだ。次にこうしてみた。

java -Xmx32g -XX:+PrintFlagsFinal | grep UseCompressedOops

結果は false でした。どうやら、最大 java ヒープサイズを 32GB 以上に設定すると、自動的に UseCompressedOops は無効化される模様。なんで、Compressed Oops の存在を知らなくても、JVM勝手に自動的に最大ヒープサイズに応じて調整してくれるわけだ。じゃ、これはどうでしょう。

java -Xms32g -XX:+PrintFlagsFinal | grep UseCompressedOops

結果は、true でした。現状の実装では、java ヒープの初期値を 32GB 以上に設定しても、UseCompressedOops は無効化されないようで(Java SE 6 Update 29 で確認)。なんで、私が試した限り、マシンにいくら物理メモリを搭載していたとしても、以下のように初期ヒープサイズを 32GB を超えるようなオプション設定だとアプリケーションが全く動作するそぶりを見せずにいきなり JVM がクラッシュするよ。

java -Xms35g jp.ne.quitada.HogeHoge

-Xmx を明示的に指定せずに、-Xms を指定って、あまりないかもしれないけど、これってバグっぽくね?

ま、ワークアラウンドとしては、以下のように UseCompressedOops を明示的に無効にすればよいけど。

java -Xms35g -XX:-UseCompressedOops jp.co.quitada.HogeHoge