본문

Tech
JVM Crashのトラブルシューティング

작성일 2019.03.15

%EA%B7%B8%EB%A6%BC7.png

Webアプリケーションのパフォーマンスが低下したり障害が発生した場合は、アプリケーションのパフォーマンス分析サービスを使用して、アプリケーションの内部動作をすばやく表示できるようにする多くの問題を解決できます。WhaTap Labsはアプリケーションのパフォーマンス分析サービスを開発する会社ですが、お客様に代わって直接アプリケーションの問題を分析して解決することもあります。

アプリケーションの問題の間に多くの顧客が苦労するケースはJVM Crashです。JVM Crashは、JVM自体が外部要因で終了する場合であるため、アプリケーションパフォーマンス分析サービスとして見られる情報は限られていますが、代わりにGoogle検索やIBMサイトなどのさまざまなパスで解決できます。それでは、JVM Crashの問題を解決する方法をお教えします。

JVM Crash

jvm_crash.webp

Java仮想マシン(JVM)は、Javaプログラムが実行される仮想マシンです。1つのVMなので、内部でシグナルを与えないと終了しないように設計されています。逆に、PCでたまに出会うブルースクリーンのような理由がわからなく止まることもあります。この場合を JVM では Crash といいます。

JVM Crashは発生頻度が低く、原因も作成したアプリケーションに起因しないため、開発者は原因を特定するのが困難です。しかし、PCで出会うブルースクリーン画面にもエラーコード、メモリアドレスが出てくるように、JVMも死ぬ前に糸口を震わせていきます。

JVMもアプリケーションです。

jvm_also_application.webp

アプリケーションはすべてのバグで平等です。一定の規模を超えるすべてのアプリケーションは、重要またはマイナーなBugを持っています。

JVMも当然Bugがあります。そしてそのバグがCrashを作ったりもします。アプリケーションの問題としてJVMにCrushが発生するのもJVMの問題です。この場合でも正常なJVMであれば、アプリケーションのエラーを親切にException, Errorとして知らせてCrashされることはないはずです。JVMが未知の理由でCrushした場合、それはJVM Bugです。

IBM JDK 8.0 Fix List ホットキーIBM JDK 8.0 Fix List ホットキー

幸いなことに、JDKのバグフィックスリストを簡単に見つけることができます。IBMの場合、タイプ別にCrash、Hang、Performanceなどに分類しておきます。以下は8.0フィックスパックのリストです。Defect Typeを見ると、Crash、Issue、Hangなどに分類されたものが見られます。

ij11480_crash_in_ffisys_call_in_zos.webp

上記のバグ修正リストでIJ11480:CRASH IN FFISYS CALL IN ZOSを選択すると、以下のようにそのバグの詳細が表示されます。

もちろん、Oracleでもバグフィックスリストを管理しています。

Oracle JDK Fix List ホットキー

JVMが死ぬ前に残したエラーログを見つける

JVM が異常終了すると hs_err_pid(hotspot), javacore(IBM)を残すようになっています。ただし、ログが生成されていないか見つからない場合は、関連する環境変数、オプションなどを適用してログが残るようにする必要があります。

ログファイルが作成される場所がわからない場合は、次のようにログファイルを作成する場所を指定してください。

Oracleの場合はproduct flagを使用します。

XX:ErrorFile=/var/log/java/hs_err_pid%p.log

Java Platform, Standard Edition Troubleshooting Guide > Location of Fatal Error Log

IBM の場合は、.profile 環境変数を使用します。

export IBM_JAVACOREDIR=/somewhere/dumpdir

Changing the location of javacore, heapdump and core file generated by TIP

それでもログが残っていない場合は、次の状況を疑うことができます。

  • /tmp usage full : /tmp ファイルシステムが満杯の場合、ログは記録されません。
  • 権限の問題: javaプロセスを実行しているアカウントがターゲットパスに書き込み権限を持っていなくてもログは記録されません。この場合、JVMオプションにログパスを設定します。
  • JVM Bug: JVM Crashもバグ、Crashログを記録できないのも結局JVM Bugです。 原因解明が非常に難しい。

エラーログの見方

以下は、Oracle hotspot hs_err_pidの内容です。 上部には発生理由と発生位置があります。

blog_28_code_01.webp

ここでSIGSEGVはSegmentation faultを意味し、Crashの発生理由です。

その他代表的な発生事由で

  • ユーザーの kill -3 で発生した SIGQUIT
  • OOME(OutOfMemoryError)で発生したOut of Memory Error
  • StackOverFlow で発生した StackOverFlow

Problematic frameは発生位置を示します。

上記の例は、libjvm.soの0x7c091bの場所で発生したと記録されているため、ユーザーが実装した領域のエラーではないことがわかります。

同じファイルをもっと詳しく見てみましょう。

blog_28_code_02.webp

Dumpの内容を確認すると、0x7c091bはJava Compilerが呼び出したNodeであることがわかります。Java bytecodeを機械語に翻訳する過程で発生したJVMエラーでCrashが発生したと判断できます。

IBM Javaの場合はjavacoreを残します。Oracle hotspotと同様に、上部に発生理由と発生場所があります。

blog_28_code_03.webp

発生の理由である Dump Event "gpf" は general protection fault であり、Segmentation fault と同じです。

やはり下にModule: /usr/java8_64/jre/lib/ppc64/compressedrefs/libj9thr29.soという発生位置が記録されています。

Googleに尋ねる

クラッシュの原因が SIGSEGV(Segmentation fault)または gpf(general protection fault)で、発生位置がJDK 内部モジュールである場合は、JDK Fixで問題を解決できます。

Oracle Hotspotのログでlibjvm.soの0x7c091bでエラーが発生したことを確認したら、Googleでその行を検索します。

blog_28_code_04.webp

%EA%B7%B8%EB%A6%BC16.png

検索すると、その行のバグを確認してみることができます。ステータス値が CLOSED です。対応するバグ修正を探すだけです。https://bugs.openjdk.java.net/browse/JDK-8183197

下部のCommentsを確認してください。バグ修正へのリンクを見つけることができます。

bug_openjdk_java_net_activity_comment.webp

以下のリンクで、より詳細な情報を見つけることができます。 https://bugzilla.redhat.com/show_bug.cgi?id=1306558

bugzilla_redhat_com.webp

これで、そのJDKバージョン以降のフィックスリストを確認して更新計画を立てることができます。ただし、アップデートを計画するのではなく、問題の回避方法を使用して、バグの原因に基づいてアプリケーションの構造を変更することもできます。このような場合は、アプリケーションパフォーマンス分析ツールが役に立ちます。

まとめ

JDKも誰かが作成したアプリケーションです。 JDKもエラーの可能性を暗示していることを常に認識し、定期的なアップデートでより信頼性の高い環境を作成する必要があります。また、アプリケーションのパフォーマンスを上げる必要がある場合、またはアプリケーションで発生した問題が解決しない場合は、WhaTap Labs(support@whatap.io)までメールください。できるだけお手伝いさせていただきます。

WhaTap Monitoringを体験してみましょう。
難しかったモニタリングと分析が容易に実現できます。