JIT コンパイラ関連オプションの挙動
Oracle Java 6 での JIT コンパイラ関連のオプションとその挙動についての記述。とはいえ大きく挙動を変えられるような実装ではありませんので以下の 3 つを押さえておけば良いかと思います。
-XX:CompileThreshold=10000 | JIT コンパイルを行うまでのメソッド呼び出し回数または分岐回数 |
-XX:+CITime | プログラム終了時に JIT コンパイラの実行統計を出力 (JDK 1.4.0 以降) |
-XX:+PrintCompilation | JIT コンパイル実行時にメッセージを出力 |
他に -Xint (JIT コンパイルを行わない), -Xbatch (フォアグラウンドで JIT コンパイルを行う) オプションもありますが、これらは JIT コンパイラの実装が貧弱で混沌としていた時代の名残です。今時は興味実行以外での利用機会もないので無視します。
実行サンプルに末尾再帰でフィボナッチ数 を求めるプログラムについて。メソッド fibonacci() は引数 に対して合計値がそのフィボナッチ数となる 2 つの要素を返します。
import java.math.*; public class A{ private static final BigDecimal[] fibonacci(int n){ if(n == 0){ return new BigDecimal[]{ BigDecimal.ZERO, BigDecimal.ZERO }; } if(n == 1){ return new BigDecimal[]{ BigDecimal.ZERO, BigDecimal.ONE }; } BigDecimal[] f = fibonacci(n - 1); return new BigDecimal[]{ f[1], f[0].add(f[1]) }; } public static void main(String[] args){ long t0 = System.nanoTime(); BigDecimal[] f = fibonacci(10000); System.out.printf("%.3fms%n", (System.nanoTime() - t0) / 1000000.0); System.out.printf("%s%n", f[0].add(f[1])); return; } }
実行統計の出力
-XX:+CITime オプションを使用するとプログラム終了時に JIT コンパイラの実行統計が出力されます。
torao@safran$ java -XX:+CITime A 28.132ms 5443837311356528133…97501 Accumulated compiler times (for compiled methods only) ------------------------------------------------ Total compilation time : 0.046 s Standard compilation : 0.046 s, Average : 0.004 On stack replacement : 0.000 s, Average : nan Total compiled bytecodes : 2212 bytes Standard compilation : 2212 bytes On stack replacement : 0 bytes Average compilation speed: 48146 bytes/s nmethod code size : 9408 bytes nmethod total size : 17256 bytes
コンパイルごとの出力
-XX:+PrintCompilation オプションは JIT コンパイルが行われるたびにメッセージを表示します。以下の実行では fibonacci() メソッドと共に実行回数の多い BigDecimal のメソッドがコンパイルされています。
torao@safran$ java -XX:+PrintCompilation A 74 1 A::fibonacci (73 bytes) 81 2 java.math.BigInteger::add (178 bytes) 93 3 java.lang.Object::<init> (1 bytes) 95 4 java.lang.Number::<init> (5 bytes) 103 5 java.math.BigDecimal::<init> (27 bytes) 31.522ms 125 6 java.math.BigDecimal::add (302 bytes) 135 7 java.math.MutableBigInteger::mulsub (110 bytes) 138 8 java.math.MutableBigInteger::primitiveLeftShift (89 bytes) 142 9 java.math.BigInteger::<init> (24 bytes) 145 10 java.math.MutableBigInteger::unsignedLongCompare (20 bytes) 147 11 java.math.MutableBigInteger::divideMagnitude (594 bytes) 163 12 java.math.MutableBigInteger::normalize (91 bytes) 5443837311356528133…97501
コンパイルしきい値の調整
-XX:CompileThreshold オプションを使用して JIT コンパイルの行われるタイミングを調整することができます。デフォルトの 10000 を基準に、アプリケーション起動からなるべく早めに JIT コンパイルを済ませたい場合は少ない数値を、JIT コンパイルの影響をなるべく分散させたい場合は大きな値を指定します。以下の例では 1 を指定しているのでブートストラップからほとんどのメソッドが JIT コンパイルされています。
torao@safran$ java -XX:CompileThreshold=1 -XX:+CITime -XX:+PrintCompilation A --- n java.lang.Thread::currentThread (static) --- n java.lang.System::arraycopy (static) --- n java.security.AccessController::getStackAccessControlContext (static) --- n java.security.AccessController::getInheritedAccessControlContext (static) --- n java.lang.Thread::setPriority0 81 2 java.lang.Object::<init> (1 bytes) 85 3 java.lang.Thread::init (193 bytes) … --- n java.lang.Double::longBitsToDouble (static) --- n java.lang.Float::floatToRawIntBits (static) --- n java.io.FileOutputStream::writeBytes 236.170ms 5443837311356528133…97501 Accumulated compiler times (for compiled methods only) ------------------------------------------------ Total compilation time : 2.239 s Standard compilation : 2.239 s, Average : 0.003 On stack replacement : 0.000 s, Average : nan Total compiled bytecodes : 79292 bytes Standard compilation : 79292 bytes On stack replacement : 0 bytes Average compilation speed: 35407 bytes/s nmethod code size : 362752 bytes nmethod total size : 688752 bytes