動的コンパイルについて説明します。
C/C++やCOBOLなどで作られたプログラムを実行する場合は、各言語に対応したコンパイラによって、プログラムのソースコードを実行対象プラットフォーム上で動作可能な機械命令へ翻訳(後述の動的コンパイルとの対比で静的コンパイルと呼ばれることがあります)し、事前にプラットフォーム依存の実行バイナリを作成する必要があります。
Javaで作られたプログラムを実行する場合は、javacコマンドによって、プログラムのソースコードをJava VMが解釈/実行できる命令「バイトコード」へ変換し、事前にプラットフォーム非依存の実行バイナリである「クラスファイル」を作成する必要があります。
Javaの実行環境であるJava VMが起動された後、Java VMは、実行対象プログラムであるクラスファイルを読み込み、クラスファイルを以下の2つの方法を用いて実行します。
インタプリタによるバイトコードの実行
Java VMのインタプリタは、クラスファイル内のバイトコードを1命令ずつ解釈して実行します。
機械命令の実行に比べ、実行速度が低速になります。
動的コンパイルにより、バイトコードを機械命令に翻訳してから実行
Javaアプリケーションの実行中、Java VMは、クラスファイル内のJavaメソッドに対応するバイトコードを、実行対象プラットフォーム上で動作可能な機械命令へ自動的に翻訳してから実行します。Javaアプリケーション実行中に自動的に行われる翻訳処理であるため、その翻訳処理を動的コンパイルと呼びます。
インタプリタによるバイトコードの実行に比べ、高速に実行できます。
なお、動的コンパイル処理は、翻訳時における機械命令の最適化処理で必要となる各Javaメソッドの実行頻度や呼び出し関係などの情報を、Javaアプリケーション実行と同時に行われる各Javaメソッドに関するプロファイリング処理の結果から得ます。そのため、プロファイリング処理によりある程度の情報量が得られるまで何度か再翻訳が繰り返され、次第にJavaアプリケーションの実行状況に合った翻訳結果に最適化されることで、機械命令部分の実行性能が向上する傾向があります。
Java VMが行う動的コンパイル自体は、Javaアプリケーションの実行から見ると、オーバーヘッド部分になります。そのため、インタプリタによる実行性能(低速)、動的コンパイルによるオーバーヘッド、および動的コンパイル結果である機械命令による実行性能(高速)の三者をバランス良く調整することで、Javaアプリケーション全体としての実行性能を良くする必要があります。
Java VMは、実行頻度の高いJavaメソッドを優先的にコンパイルし、あまり使われることのないJavaメソッドはインタプリタ実行のままにすることで、インタプリタ実行、動的コンパイル、および動的コンパイル結果である機械命令実行のバランスを取り、Javaアプリケーション全体としての実行性能を良くする調整を行っています。
なお、実行対象となるJavaアプリケーション内で、各Javaメソッドの実行頻度は、実際にJavaアプリケーションが実行されない限り分かりません。そのため、Java VMはJavaアプリケーション実行と同時に各Javaメソッドに関するプロファイリング処理を行い、その結果を用いて動的コンパイルの対象となるJavaメソッドを決定しています。プロファイリング処理によりある程度の情報量が得られるまで、すなわちJava VM起動直後はインタプリタ実行だけですが、次第にインタプリタ実行と動的コンパイル結果による機械命令実行との混合動作になります。
動的コンパイルに関する以下の機能を独自機能として実装しています。
動的コンパイル発生状況のログ出力機能については、“7.3 動的コンパイル発生状況のログ出力機能”を参照してください。
Java VMはJavaアプリケーションとして実行されるJavaメソッドに対して必要に応じて自動的にコンパイル処理を行いますが、コンパイル処理を行っている際にコンパイラ内で何らかの異常が発生すると、当該Javaメソッドに対するコンパイル処理だけでなくJava VMとしての動作も異常状態として停止させてしまう場合があります。
コンパイラ内で何らかの異常が発生した場合に自動的にリカバリ処理を行い、Java VMとしての動作を継続させる機能を「コンパイラ異常発生時の自動リカバリ機能」として実装しています。
本機能によるリカバリ処理が行われた際にコンパイル対象となっていたJavaメソッドは、リカバリ処理実施後は、コンパイル処理の対象とはなりません。当該Javaメソッドについてはコンパイルされず、インタプリタのままJavaアプリケーションとしての実行が継続されます。
リカバリ処理実施後に通知を受け取るオプション
本機能は内部処理として動作する機能であるため、コンパイラ内で何らかの異常が発生してもリカバリ処理が正常に行われた場合には、外部に対する通知などは何も行いません。リカバリ処理が正常に行われた場合でもコンパイラ内で何らかの異常が発生したことを情報として受け取る場合には、以下のオプションを指定してください。
-XX:+PrintCompilerRecoveryMessage |
リカバリ処理実施後に通知を受け取るオプションを指定した場合の出力形式
CompilerRecovery: Information:The compilation was canceled for method method_name Reason for the cancellation: reason [code:c, addr:xxxxxxxx] |
リカバリ処理の情報が上記の形式で標準出力に出力されます。
コンパイル処理で異常が発生した際にコンパイル対象となっていたJavaメソッドの名前。
コンパイル処理で発生した異常の原因情報。原因情報として以下の項目があります。
assert: コンパイル処理で内部処理矛盾を検出した
error: コンパイル処理で何らかの誤りを検出した
stack overflow: コンパイル処理でスタックオーバーフローを検出した
異常コード。
コンパイル処理で異常が発生した際のアドレス。
Java VMはJavaアプリケーションとして実行されるJavaメソッドに対して必要に応じて自動的にコンパイル処理を行い、通常はごく短時間でその処理を完了します。
しかし、コンパイル処理自身や同じJavaプロセス内で動作させている他の処理の障害などによりCPU資源が占有され続けてしまうと、数分を経過してもコンパイル処理が終了しない場合が考えられます。このような状態が継続すると、システム全体に対して悪影響を与える可能性が考えられます。
このため、各Javaメソッドのコンパイル処理に要している時間を監視し、コンパイル処理で必要と考えられる程度の時間を経過してもコンパイル処理が終了していない場合には、Javaプロセス内の処理で何らかの問題が発生していると判断し、当該Javaプロセスを強制的に終了させる機能を「長時間コンパイル処理の検出機能」として実装しています。
長時間コンパイル処理の検出機能を有効にするオプション
以下のオプションでコンパイル処理に対する監視時間(コンパイル処理に要する時間の上限値)を指定した場合に有効となります。ただし、オプション値として「0」を指定した場合には、本機能は有効となりません。
以下のオプションで指定された時間を超過してもコンパイル処理が終了していない場合、本機能はJavaプロセス内の処理で何からの問題が発生していると判断し、当該Javaプロセスを強制的に終了させます。
-XX:CompileTimeout=nn |
コンパイル処理に要する時間の上限値(単位:秒)を指定します。デフォルト値は「0」であり、本機能は無効となっています。
なお、本機能による時間監視の最小単位は30秒であるため、その単位での時間誤差があります。
長時間コンパイル処理の検出機能によるJavaプロセス強制終了時の出力メッセージ
本機能によってJavaプロセスを強制終了する場合、以下のメッセージを標準出力に出力し、コアダンプを出力して終了します。
CompilerRecovery: Information: CompilerRecovery got the VM aborted |
コンパイラスレッドの内部識別子
本機能によるチェックで異常が検出された際にコンパイル対象となっていたJavaメソッドの名前
注意
長時間コンパイル処理の検出機能に対する注意事項
何らかの要因によりJavaプロセス内のコンパイル処理へCPU資源が十分に割り当てられず、コンパイル処理自体が進んでいない場合でも、コンパイル処理開始から-XX:CompileTimeoutオプションで指定された監視時間を超過した場合には、本機能によって当該Javaプロセスの強制終了となります。
このため、当該Javaプロセスを実行するシステムのCPU負荷が高い場合には、コンパイル処理に対してCPU資源が十分に割り当てられず、この結果として本機能による強制終了が発生する可能性が考えられます。
本機能による強制終了が発生した場合には、以下の事項を確認してください。
当該Javaプロセスを実行しているシステムのCPU資源量は十分か。
当該Javaプロセス以外の他のプロセスでCPU資源が占有されていないか。
“-XX:CompileTimeout=0”を指定した場合に本機能による強制終了が回避され、かつ、当該Javaプロセスが正常に終了する、または未負荷時に正常なアイドル状態に遷移するか。
上記事項に合致する場合は、コンパイル処理に対してCPU資源が十分に割り当てられなかった結果として発生した強制終了と考えられます。
長時間コンパイル処理の検出機能を有効にしてこの状態が発生した場合には、“-XX:CompileTimeout”オプションで指定する監視時間として、より大きな値に設定してください。
参考
長時間コンパイル処理の検出機能に対する監視メッセージの出力
以下のオプションを指定した場合、Javaメソッドのコンパイル処理において1分が経過すると、「長時間コンパイル処理の検出機能が出力する監視メッセージ」の形式で監視メッセージが出力されます。
その後は、30秒経過するごとに同じ監視メッセージが出力されます。
なお、本機能による時間監視の最小単位は30秒であるため、その単位での時間誤差があります。
長時間コンパイル処理の検出機能の監視メッセージ出力を有効にするオプション
-XX:+PrintCompilerRecoveryMessage |
長時間コンパイル処理の検出機能が出力する監視メッセージ
CompilerRecovery: Information: The compiler thread(0xnnnnnnnn) might not return from compiling method method_name. |
コンパイラスレッドの内部識別子
本機能によるチェックで検出された際にコンパイル対象となっていたJavaメソッドの名前