Javaの最適化の議論で「インライン展開」「エスケープアナリシス」などの用語が出てきていて、気になって調べたところ、java実行時のオプションで最適化の方法を指定したり実行過程を表示したり出来るらしい。
主なオプションについて
Java HotSpot VM Optionsにパフォーマンスに影響しそうなHotSpot VMのオプションが説明されている。
例:
オプション | 効果 |
---|---|
-XX:+PrintCompilation | メソッドがコンパイルされた際にメッセージを表示 |
-XX:+UseBiasedLocking | Biased Lockingを使用する |
-XX:+OptimizeStringConcat | 可能なら文字列の連結操作の最適化を行う |
-XX:+AggressiveOpts | 将来のリリースでデフォルトになりそうな最適化フラグを有効にする |
... | ... |
たとえばjava起動時に-XX:+PrintCompilationを指定すると、どのタイミングでどのメソッドがJITコンパイラにコンパイルされたかが表示され、最適化の様子をある程度確認することが出来る。
フラグ設定値の表示
追記: こちらに良い解説ページがあったので詳しくはそちらを見てください。
java起動時に"-XX:+PrintFlagsFinal"を指定すると、その実行で最終的に使用するフラグの値を表示する。*1
C:\Java\jdk1.6.0_25\bin>java -XX:+PrintFlagsFinal -server -version [Global flags] uintx AdaptivePermSizeWeight = 20 {product} uintx AdaptiveSizeDecrementScaleFactor = 4 {product} uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product} uintx AdaptiveSizePausePolicy = 0 {product} uintx AdaptiveSizePolicyCollectionCostMargin = 50 {product} uintx AdaptiveSizePolicyInitializingSteps = 20 {product} uintx AdaptiveSizePolicyOutputInterval = 0 {product} uintx AdaptiveSizePolicyWeight = 10 {product} uintx AdaptiveSizeThroughPutPolicy = 0 {product} uintx AdaptiveTimeWeight = 25 {product} bool AdjustConcurrency = false {product} bool AggressiveOpts = false {product} ...
おそらく使用される全てのフラグの型、フラグ名、使用値が表示される。
「{product}」というのがリリース版で使用できるフラグ、「{C2 product}」というのがさらに-serverで起動した際に使用できるフラグのようだ。
UseXX系のような最適化などを有効にするフラグ、TraceXXやPrintXX系のような動作状況を表示するフラグがいろいろある。
ここに表示されるフラグの値を変えるには、たとえばboolの場合「-XX:+フラグ名」(有効にする場合)、「-XX:-フラグ名」(無効にする場合)などのようにオプションで指定できる。
名称からある程度は推測できるとはいえ、フラグの意味がわからないと使いようがないけど、それについてはfastdebug版のバイナリで「-XX:+PrintFlagsWithComments」付きで起動すると簡単な説明が表示される。
C:\Java\jdk1.6.0_25\fastdebug\bin>java -XX:+PrintFlagsWithComments -server -version
たとえば-XX:+TraceBiasedLockingについては、以下のように説明が表示される。
bool TraceBiasedLocking = false {product} Trace biased locking in JVM
fastdebug版はJDKのBinary Snapshot Releasesのサイト(http://download.java.net/jdk6/)から「DEBUG」の欄にあるjarファイルをダウンロードし、ローカルでjarを実行するとインストールして使うことが出来る。今回はWindows版を使用した。
「-XX:+AggressiveOpts」で何が有効になるか調べる
「-XX:+AggressiveOpts」あり・なしで起動した際のフラグを「-XX:+PrintFlagsFinal」で表示させて差分を取る。*2
C:\Java\jdk1.6.0_25\bin> java -XX:+PrintFlagsFinal -XX:+AggressiveOpts -server -version >C:/TEMP/opt1 C:\Java\jdk1.6.0_25\bin> java -XX:+PrintFlagsFinal -server -version >C:/TEMP/opt2 C:\Java\jdk1.6.0_25\bin> diff -y --suppress-common-lines C:/TEMP/opt1 C:/TEMP/opt2 bool AggressiveOpts := true | bool AggressiveOpts = false intx AutoBoxCacheMax = 20000 | intx AutoBoxCacheMax = 128 intx BiasedLockingStartupDelay = 500 | intx BiasedLockingStartupDelay = 4000 bool DoEscapeAnalysis = true | bool DoEscapeAnalysis = false bool EliminateAutoBox = true | bool EliminateAutoBox = false bool UseLoopPredicate = true | bool UseLoopPredicate = false
jdk1.6.0_22のデフォルトでは「DoEscapeAnalysis」「UseLoopPredicate」などは有効になっていないようだ。
実際のコンパイル内容を表示する
最適化によって実際にどんな風に実行内容が変更されているかを確認したい場合はどうすればよいか。
「JITの出力するx64アセンブリを深追いしてみた - 川口耕介のブログ」によるとfastdebug版のjavaで「-XX:+PrintOptoAssembly」をつけて実行すると都度のコンパイル結果がアセンブラで表示されるらしい。
やってみたところ確かに表示されたが内容は正直よくわからなかった……
追記: Sun WikisのPerformanceTechniques解説ページ
HotSpot JVMのパフォーマンスを上げるためのハウツーを詳しく書いたページがあったので貼っとく。
http://wikis.sun.com/display/HotSpotInternals/PerformanceTechniques