Javaアプリケーションは、様々な理由で動作を停止する場合があります。最も一般的な理由は、アプリケーションの動作が完了したこと、または正常に中断したことです。その他の理由としては、Javaアプリケーション・エラー、処理できない例外、またはOutOfMemoryError
などの回復できないJavaエラーが考えられます。場合によっては、JVM自体で正常に回復できなかった問題が起きたことを意味する、JRockit JVMクラッシュが発生する可能性があります。
この章では、JVMのクラッシュを診断し、解決する方法を説明します。この章の内容は次のとおりです。
JVMクラッシュの診断と解決の第一段階は、クラッシュの分類です。つまり、クラッシュが発生した場所および原因を特定します。
JRockit JVMはクラッシュすると、クラッシュした時点でのコンピュータとJVMプロセスの状態のスナップショットを作成し、状態情報を次のクラッシュ・ファイルに書き込みます。
.dumpファイル: .dump
ファイルは、クラッシュした時点でJVMが動作していた完全なメモリー・イメージおよび環境の実行サマリーのようなテキスト・ファイルです。このファイルは、クラッシュ時にJVM自身によって作成されるファイルで、クラッシュの分類に役立ちます。場合によっては、このファイルを修復済みの問題の特定にも使用できます。このファイルから、問題の原因を判断するための十分な情報が得られることはほとんどありません。
.core
ファイル: .core
ファイルはLinuxやSolarisのようなUNIX系のシステムで生成されるバイナリ・クラッシュ・ファイルです。デフォルトで、.core
ファイルは、クラッシュした時点での全JVMプロセスに関する完全な情報をキャプチャします。
.mdmp
ファイル(ミニダンプ・ファイル): .mdmp
ファイルは、前述した.core
ファイルに相当するWindows版のファイルです。
オラクルとサポート契約を結んでいる場合は、JRockit JVMの問題のトラブルシューティングについてOracleサポートへのご連絡が可能です。バイナリ・クラッシュ・ファイル(.core
または.mdmp
)はOracleサポートへのご連絡時に必須の情報です。
クラッシュ・ファイルの詳細は、第8章「クラッシュ・ファイルの概要」を参照してください。
表6-1に、発見可能な症状と、その症状に対して予想されるクラッシュの種類の一覧を示します。
表6-1 クラッシュの症状とクラッシュの種類
症状 | トラブルシューティング情報は、次を参照してください |
---|---|
|
|
|
|
|
|
Linuxのみの場合:
|
6.4項「サポートされないLinux構成が原因のクラッシュ」 |
Linuxのみの場合: 非標準またはサポートされないLinux構成を使用しています。 |
6.4項「サポートされないLinux構成が原因のクラッシュ」 |
この表の一覧のいずれにも当てはまらない症状が検出されました。 |
|
JVMは、Javaヒープ、Javaメソッド、スレッド・スタックおよびJVM内部データ構造など、様々な目的で仮想メモリーを確保します。さらに、ネイティブ(JNI)コードでも、メモリーを割り当てることができます。プロセス・サイズは、JVMによって確保されたすべてのメモリーとプロセス内で実行中のあらゆるサードパーティ・ライブラリから構成され、オペレーティング・システムの制限に従います。
JVMプロセスの仮想メモリー割当てがオペレーティング・システムの制限を超えると、JVMで仮想メモリーが不足し、クラッシュが発生する可能性があります。
この項の内容は次のとおりです。
仮想メモリー不足エラーのトラブルシューティングを開始する前に、まず、エラーが本当にJVMプロセスでの仮想メモリー不足によるものであるのかを確認する必要があります。
表6-2に、32ビットの各種オペレーティング・システム上のシングル・プロセスで使用可能な仮想メモリーの最大値を示します。64ビットのプラットフォームでは、仮想メモリーは実質的に無制限です。
表6-2 IA32アーキテクチャで使用可能な仮想メモリーの概算の最大値
オペレーティング・システム | 仮想メモリーの概算の最大値 |
---|---|
Windows |
2GB |
Windows /3GB起動オプション |
3GB |
Linux(標準) |
3GB |
仮想メモリー不足エラーの発生の有無は次の方法で確認できます。
テキスト・クラッシュ・ファイルを調べます。
テキスト・クラッシュ・ファイル(.dump
)は、メモリーの割当てに失敗したことを示す可能性があります。これは、JRockit JVMプロセスで仮想メモリーが不足していることを顕著に示しています。テキスト・クラッシュ・ファイルの詳細は、第8章「クラッシュ・ファイルの概要」を参照してください。
バイナリ・クラッシュ・ファイルのサイズをチェックします。
JRockit JVMがクラッシュすると、バイナリ・クラッシュ・ファイル(.core
または.mdmp
)が生成されます。デフォルトでは、バイナリ・クラッシュ・ファイルにはJVMプロセス全体のコピーが含まれます。
バイナリ・クラッシュ・ファイルのサイズをチェックして、JVMプロセスで本当に仮想メモリーが不足しているかどうかを判断してください。
バイナリ・クラッシュ・ファイルのサイズが、コマンドライン・オプションの-XXdumpSize
またはオペレーティング・システム・コマンドのulimit
(LinuxおよびSolarisのみ)を使用して制限されていないことを確認します。コマンドulimit -a
を使用して、LinuxおよびSolarisでクラッシュ・ファイルのサイズが無制限であることを確認してください。バイナリ・クラッシュ・ファイルのサイズが制限されていると、このコマンドを使用してJVMプロセスで仮想メモリーが不足しているかどうかを確認できません。
バイナリ・クラッシュ・ファイルのサイズが、ヒープのサイズより大きいかどうか確認します。これは、バイナリ・クラッシュ・ファイルが(ディスク領域の制限などによって)切り捨てられていないことを確認するためのサニティ・チェックです。
バイナリ・クラッシュ・ファイルのサイズが、オペレーティング・システムによって許可されているプロセスの最大サイズに近づいているかどうかをチェックします(表6-2を参照)。
JVMプロセスで仮想メモリーが不足していることを確認したら、この項の説明に従って問題のトラブルシューティングを開始できます。
最新のJRockit JVMリリースを実行していることを確認してください。JVMクラッシュの原因となるメモリー使用量の問題が、最新のJRockit JVMリリースで修正されている可能性があります。
Javaヒープは、JVMで使用されるメモリーの合計の一部に過ぎません。Javaヒープが大き過ぎると、Javaメソッドがコンパイルおよび最適化される際、またはネイティブ・ライブラリが読み込まれる際に、JVMが起動できないか、または仮想メモリーが不足する場合があります。このような状況が発生する場合、最大ヒープ・サイズを下げてみる必要があります。
Windows 2000 Advances ServerおよびDatacenter、Windows 2003、Windows XPおよび以降のWindowsバージョンでは、/3GBオプションで(BOOT.INI
ファイルでオプションを指定して)オペレーティング・システムを起動するオプションがあります。このオプションを指定すると、最大仮想メモリー・プロセス・サイズは2GBから3GBに変更されます。
使用しているJNIコードにメモリー・リークがないかをチェックします。JNIコードが適切に記述または使用されていないと、メモリー・リークが発生する場合があります。これにより、プラットフォームでの仮想メモリーの最大サイズに達するまで、Javaプロセスが増大します。
仮想メモリーの使用状況を記録すると、仮想メモリー不足の問題の識別に役立ちます。
この項では、WindowsおよびLinuxで仮想メモリーの使用状況の統計を集める方法を説明します。
Windowsでの仮想メモリーの使用状況の記録
Windowsツールのperfmonを使用して、PrivateBytes
プロセス・カウンタを記録します。JVMプロセスで予約された仮想メモリーの量に関する情報を収集してください。次の手順に従います。
「管理ツール」の「パフォーマンス・モニター」を開きます。
「+」をクリックして「カウンタの追加」ダイアログ・ボックスを開きます。
「パフォーマンス・オブジェクト」リストで「Process」を選択します。
「Process」のリストから「Private Bytes」のカウンタを選択します。
監視するプロセスを選択して「追加」をクリックします。
Linuxでの仮想メモリーの使用状況の記録
仮想メモリーの使用状況を、一定の間隔で記録するためのスクリプトを作成します。
例: top -b -n 10 > virtualmemory.log
このスクリプトは10秒おきにtop
を実行し、そのデータをvirtualmemory.log
ファイルに記録します。
実行中の全プロセスの仮想メモリー使用量が、ログ・ファイルのVIRT
列に記録されます。現在のステータスだけを確認するには、top
と入力して[Shift]
+[M]
を押し、出力をメモリー使用量でソートします。これで、通常はJVMプロセスが出力の一番上に並びます。
virtualmemory.log
のような記録を作成すると、JRockit JVMプロセスが実際に増加しているかどうかを確認し、増加の証拠としてOracleサポートに提示できるので便利です。
この項に示されている解決策を試しても問題を解決できない場合は、第9章「サポートに関するオラクルへの連絡」の説明に従ってOracleサポートにご連絡ください。
スタック・オーバーフローのクラッシュは、JRockit JVMがスタック・オーバーフローのエラーを適切に処理できない場合に起こります。J2SE Javadocによると、java.lang.StackOverflowError
が適切に処理されると、JVMが壊れているか、処理を続けるために必要なリソースが不足していることを示すためにjava.lang.VirtualMachineError
がスローされます。
詳細は、次のJ2SE java.lang
Javadocを参照してください。
Java SE 6:
クラスStackOverflowError
http://java.sun.com/javase/6/docs/api/java/lang/StackOverflowError.html
クラスVirtualMachineError
http://java.sun.com/javase/6/docs/api/java/lang/VirtualMachineError.html
J2SE 5.0:
クラスStackOverflowError
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StackOverflowError.html
クラスVirtualMachineError
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/VirtualMachineError.html
JRockit JVMの.dump
ファイルには、スローされたスタック・オーバーフロー・エラーの数に関する情報が記録されます。
スタック・オーバーフローが原因でJRockit JVMがクラッシュすると、テキスト・クラッシュ・ファイル(.dump
)の一番上のあたりにError Message: Stack overflow
と表示されます。その他にクラッシュ・ファイルのスタック・トレースが極度に長い場合や、スタック・トレースがまったくない場合も、このクラッシュを示している可能性があります。.dump
ファイルにStackOverFlow: 2 StackOverFlowErrors occurred
のように表示されている場合は、以前のスタック・オーバーフローの問題によりクラッシュがトリガーされた可能性があります。
この項では、スタック・オーバーフロー・エラーの解決方法をいくつか説明します。
スタック・オーバーフロー・エラーの主な原因に、JRockit JVM のメモリー制限を超えたスタック領域を使用するようにアプリケーションが作成されていることがあります。
.dump
ファイルでスタック・トレースを確認し、スタック領域の使用量を減らすようにJavaコードを変更できないか判断します。たとえば、アプリケーション・コードには再帰的なメソッド・コールが含まれる場合があります。再帰深度が深いとStackOverflowエラーが発生する可能性があります。
アプリケーションのスタック領域の使用量を変えるのが不可能な場合は、-Xss
コマンドライン・オプションを使用してスレッドのスタック・サイズを変更できます。
-XX:+CheckStacks
コマンドライン・オプションを使用すると、JRockit JVMのスタック・オーバーフロー・エラーに対する抵抗力を強化できます。これによって、通常はJVMがダンプしなくなり、java.lang.StackOverflowError
をスローしなくなります。
-XX:+CheckStacks
コマンドライン・オプションを指定すると、JVMがスタック上のページにアクセスするので、パフォーマンスがやや低下します。
この項に示されている解決策を試しても問題を解決できない場合は、第9章「サポートに関するオラクルへの連絡」の説明に従ってOracleサポートにご連絡ください。
JRockit JVMをLinuxで実行中にアプリケーションがクラッシュした場合は、スタック・トレースにクラッシュの理由が示されていても、JRockit JVMをサポート対象のLinux構成で実行しているか確認する必要があります。
次の処理を実行します。
オペレーティング・システムのバージョンがJRockit JVMのサポート対象かどうかを確認します。
詳細は、次の場所にある「Oracle JRockit JDK Supported Configurations」を参照してください。http://www.oracle.com/technology/software/products/ias/files/fusion_certification.html
正しいglibcバイナリがインストールされているかどうかを確認します。
IA32のLinuxでは、i686アーキテクチャ用にコンパイルされたglibc
を使用するように設定される必要があります。設定されていないと、JRockit JVMがクラッシュする可能性があります。
インストールされているglibc
のバージョンをチェックするには、次のコマンドを実行します。
rpm -q --queryformat '\n%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n' glibc
出力結果がglibc 2.3.4 2.25
i386
のような場合は、サポート対象外のglibc
バイナリを使用しています。
i686アーキテクチャ用にコンパイルされたバージョンにglibc
をアップグレードします。
スレッド・ライブラリを確認します。
.core
ファイルがgdb
にある場合は、info shared
コマンドの実行によって、使用しているスレッド・ライブラリに関するヒントを得ることができます。
ロードされたlibpthread
x
.so
ファイルのパスを確認してください。
ファイルが/lib/
にある場合は、rpm
コマンドの結果を確認します。出力にi386
と示された場合は、サポート対象外のglibc
を使用しています。
i686アーキテクチャ用にコンパイルされたバージョンにglibc
をアップグレードします。
この項に示されている解決策を試しても問題を解決できない場合は、第9章「サポートに関するオラクルへの連絡」の説明に従ってOracleサポートにご連絡ください。
JVMクラッシュは、JRockit JVMのプログラミング・エラーや、サードパーティ・ライブラリのコードのエラーによって発生する場合があります。
JVMクラッシュを特定およびトラブルシューティングすることで、JRockit JVMで問題が解決されるまでの一時的な回避策を見つけることができます。また、これにより、Oracleサポートが問題を迅速に特定し解決できるようになる場合があります。
JVMクラッシュの診断およびトラブルシューティングのプロセスは、クラッシュがコード生成またはガベージ・コレクションのどちらの場合に発生したかによって異なります。
この項では、コード生成中に発生したJVMクラッシュを特定およびトラブルシューティングする方法について説明します。内容は次のとおりです。
コード生成中にJVMがクラッシュした場合、その最も一般的な原因はミスコンパイルされたメソッドです。JRockit JVMがメソッドをミスコンパイルすると、JVMがクラッシュするか、メソッドが予測されている動作とは異なる動作をします。
テキスト・クラッシュ・ファイルは、クラッシュの時点でコンパイル中であったメソッドを特定します。メソッドは、.dump
ファイルの先頭付近に存在する、Method
で始まる行で特定されます。
JRockit JVMは、最適化コンパイラの問題が原因でメソッドをミスコンパイルした可能性があります。
最適化がクラッシュの原因かどうかを調べるには、-XnoOpt
コマンドライン・オプションを指定して最適化を無効にしてから、アプリケーションを再起動します。次に例を示します。
java -XnoOpt myApplication
JRockit JVMでアプリケーションが正常に実行されれば、クラッシュの原因はコードの最適化です。
JRockit JVMは、最適化コンパイラの問題が原因でメソッドをミスコンパイルした可能性があります。
グローバル最適化を無効にした後でJRockit JVMのクラッシュが停止した場合、(前の手順で特定した)問題のあるメソッドのみを、最適化ディレクティブを使用して最適化プロセスから除外できます。問題のあるメソッドを最適化しなければアプリケーションが正しく実行される場合は、この方法で問題を解決できます。
最適化ディレクティブの指定
制御ファイルでディレクティブを指定してから、-XX:OptFile=
filename
コマンドライン・オプションを使用して制御ファイルを指定することで、JRockit JVMによるコードの最適化方法を制御できます。
注意: -XX:OptFile は内部診断オプションです。したがってこれを使用するには、-XX:+UnlockDiagnosticVMOptions をコマンドラインでも同様に、-XX:OptFile の前に付ける必要があります。 |
例6-1は、単一の最適化ディレクティブが含まれる制御ファイルが対象です。
例6-1 特定のメソッドに対するコンパイルの最適化を実行するためのディレクティブ
{ match: [ "java/lang/FloatingDecimal.dtoa*", "java/lang/Object.*"], jit: { preset : opt, } , }
例6-1のディレクティブは、メソッドを最初にコンパイルするとき、match
キーワードで指定されたパターンに一致するメソッドを最適化するようにJRockit JVMに指示します。
例6-2 特定のメソッドに対する最適化を制限するためのディレクティブ
[ { match: ["java/lang/FloatingDecimal.dtoa*", "java/lang/Object.*"], jit: { preset : opt, } , }, { match: "*", hotspot : { enable : false }, } ]
例6-2のディレクティブは、java/lang/FloatingDecimal.dtoa*
メソッドおよびjava/lang/Object.*
メソッドのみに対する最適化(hotspot
)を許可するように、JRockit JVMに指示を出します。
例6-3 メソッドのインライン化を制御するためのディレクティブ
{ match: "java.lang.*", inline: ["+java.util.*", "-com.sun.*", "sun.*" ], }
例6-3のディレクティブは、次の処理を行うようにJRockit JVMに指示を出します。
java.lang.*
からjava.util.*
へのメソッド・コールのインライン化の許可
java.lang.*
からcom.sun.*
へのメソッド・コールのインライン化の禁止
java.lang.*
からsun.*
へのメソッド・コールのインライン化の許可(可能な場合)
最適化ディレクティブの有効化
必要な最適化ディレクティブが含まれる制御ファイルを作成したら、-XX:OptFile=
filename
コマンドライン・オプションを使用して制御ファイルのパス名を指定します。
注意: -XX:OptFile は内部診断オプションです。したがってこれを使用するには、-XX:+UnlockDiagnosticVMOptions をコマンドラインでも同様に、-XX:OptFile の前に付ける必要があります。 |
最適化ディレクティブの動作の確認
ディレクティブが予測どおりに機能しているか確認するには、-Xverbose:opt
コマンドライン・オプションを使用して出力をチェックします。最適化プロセスから除外したメソッドは出力に表示されません。-Xverbose:opt
の詳細は、『Oracle JRockitコマンドライン・リファレンス』を参照してください。
最適化ディレクティブを作成するためのガイドライン
ディレクティブが適用される対象のクラスおよびメソッドのパターンを指定するには、match
キーワードを使用します。指定する値は、単一のパターンが含まれる文字列か、パターンの配列のいずれかになります。
最初にメソッドをコンパイルするときにJVMに実行させるタスクを指定するには、jit
キーワードを使用します。
インライン化が必要なメソッド・コールを指定するには、inline
キーワードを使用します。
個々のディレクティブを大カッコで囲みます。
制御ファイルは複数のディレクティブを含むことが可能で、この場合は次の条件があります。
隣り合ったディレクティブはカンマで区切る必要があります。
ディレクティブはすべて一続きで囲む必要があります。
JVMクラッシュの原因がミスコンパイルされたメソッドではないと判断した場合は、使用中の外部のインストゥルメンテーション・ツール(JProbeまたはOptimizeItなど)が問題の原因でないか調査します。これらのツールはバイトコードを書き換えることがあり、これが予期しない動作を引き起こす場合があります。
問題の原因から外部のインストゥルメンテーション・ツールを除外するには、ツールを無効にしてからアプリケーションを実行します。
外部ツールを無効にした後もJVMクラッシュが引き続き発生する場合、問題の原因はそのツールではありません。
アプリケーションが正常に実行される場合は、別のツールを使用するか、ツールを使わずに実行する必要があります。
この項に示されている解決策を試しても問題を解決できない場合は、第9章「サポートに関するオラクルへの連絡」の説明に従ってOracleサポートにご連絡ください。
コード生成のクラッシュの場合は、次のデータをOracleサポートにご提供ください。
.core
または.mdmp
ファイル
.dump
ファイル
生成中だったメソッドが含まれる.class
ファイル
生成中だったメソッドが含まれるクラスのソース・コード
この項では、ガベージ・コレクション中に発生したJVMクラッシュを特定およびトラブルシューティングする方法について説明します。内容は次のとおりです。
テキスト・クラッシュ・ファイル(.dump
)のスタック・トレースを調べることで、ガベージ・コレクションのクラッシュを特定できます。
スタック・トレースにガベージ・コレクション関数がある場合、またはクラッシュの原因となったスレッドがガベージ・コレクション・スレッドの1つである場合、クラッシュがガベージ・コレクション中に発生した可能性が最も高くなります。
スタック・トレース内のガベージ・コレクション関数は、mm
、gc
、yc
およびoc
などの接頭辞で識別されます。
JRockit JVMの最新リリースでは問題が修正されている場合があります。最新のリリースにアップグレードして、問題がまだ発生するかどうか確認します。
ガベージ・コレクタを変更する
使用中のガベージ・コレクション・モードが問題の原因である場合、別のガベージ・コレクション・モードに変更すると回避できる可能性があります。たとえば、-Xgc:pausetime
を使用中の場合は、-Xgc:throughput
への切替えを試してください。ただし、ガベージ・コレクション・モードを変更すると、JRockit JVMから同じパフォーマンス・プロファイルを得られなくなります。
確定的ガベージ・コレクション・モードを使用している場合は、別のガベージ・コレクションに変更し、なおかつ確定的ガベージ・コレクションの機能をそのまま保持することはできません。このようなケースでは、ガベージ・コレクション・モードを変更するかわりに、Oracleサポートにご連絡ください。
詳細は、『Oracle JRockitパフォーマンス・チューニング・ガイド』を参照してください。
圧縮を無効にする
ヒープ圧縮のバグにより、ガベージ・コレクション中のクラッシュを引き起こす問題が発生する場合があります。-XXcompaction:enable=false
コマンドライン・オプションを使用すると圧縮を無効にできます。
ただし、-XXcompaction:enable=false
オプションを使用するとヒープが断片化するおそれがあるため、トラブルシューティングを行う場合にのみ使用してください。ヒープが断片化されすぎると、メモリー不足エラーが発生する可能性があります。
インライン化を無効にする
誤ったインライン化によってコードが壊れ、それが原因でガベージ・コレクタがライブ・オブジェクトを追跡できなくなる場合があります。「最適化ディレクティブの指定」の説明に従って最適化ディレクティブを使用すると、インライン化を無効にできます。
最適化コンパイラを使用する
最適化を行わないJITコンパイラが原因でコードが壊れ、ガベージ・コレクタがライブ・オブジェクトを追跡できなくなっているために、ガベージ・コレクションがクラッシュする場合があります。起動時に-XX:+PreOpt
コマンドを使用し、すべてに対して最適化コンパイラを使用するように設定してください。ただし、最適化コンパイラを使用すると、JVMの起動に時間がかかる場合があります。
この項に示されている解決策を試しても問題を解決できない場合は、第9章「サポートに関するオラクルへの連絡」の説明に従ってOracleサポートにご連絡ください。Oracleサポートへのご連絡の際は、次の情報をご提供ください。
完全な.core
ファイルまたは.mdmp
ファイル(ガベージ・コレクションのクラッシュの場合)。この2つがないと、サポート・スタッフが問題を解決できません。.core
ファイルまたは.mdmp
ファイルが、少なくともJavaヒープと同じくらいの大きさであることを確認してください。
クラッシュを再現できる場合は、そのクラッシュの再現に使用した手順。
別のガベージ・コレクタを試した場合は、ガベージ・コレクタを変えることによって問題が軽減したか、あるいはどのガベージ・コレクタを使っても状況が変化しなかったか。
試してみたすべての回避策の情報。