はじめに
Semeru Runtimes/OpenJ9のプロセスが何らかの理由で異常終了したとき、OpenJ9は診断用のファイルを生成することがあります。あるいは、ユーザーの指示によって異常終了時以外にもファイルを生成させることができます。この記事ではそれらのファイルについて説明します。
javacoreファイル
診断用ファイルの一つ目はjavacoreファイルです。javacore.<日付>.<時刻>.<プロセスID>.<連番>.txtのようなファイル名になります。
異常発生時にjavaプロセス内で走っていたスレッド、メモリー内にロードされていたクラス、使用していたメモリーなどの情報が含まれています。
javacoreはテキストファイルなので、テキストエディターなどで開いて読むことができます。
javacoreファイルの内容は下記のように複数のセクションに分かれています。
TITLE
TITLEセクションにはjavacoreファイルが生成された日時などが含まれています。
GPINFO
GPINFOセクションには、メモリーアクセス違反などが発生した際にそのシグナルの内容やレジスタダンプの結果が含まれます。JITコンパイルされたメソッドの中でシグナルが発生した場合には、"Inside compiled method:" としてそのメソッド名が出力されます。
シグナル発生以外の場合には実行環境のOSのバージョンやCPUのアーキテクチャー、コア数などだけが記録されています。
このセクションに含まれるVM flagsの値から、シグナル発生時のJVMの状態を知ることができます。下記の例は"VM flags:0000000000040000"の場合で、J9VMSTATE_JNIという状態であったことが分かります (ただし、vmstate=はドキュメント化されていない非公式サブオプションです)。
$ java -Xjit:vmstate=0x40000 -version
vmState [0x40000]: {J9VMSTATE_JNI}
openjdk version "11.0.29" 2025-10-21
(以下略)
ENVINFO
ENVINFOセクションには、実行に使用したOpenJ9のバージョン、実行開始時刻、コマンドライン引数、RLIMITの設定値、環境変数の値などが含まれます。
NATIVEMEMINFO
NATIVEMEMINFOセクションには、VM、JIT、クラスライブラリが確保したネイティブメモリーのバイト数と確保回数が含まれます。ここで言うネイティブメモリーとは、C/C++のコードがmalloc()やmmap()を使ってOSから確保するメモリーを指します。
MEMINFO
MEMINFOセクションは、Javaのオブジェクトヒープ、クラス、JITコンパイラーの使うコードキャッシュ・データキャッシュなどのために確保されたメモリーのアドレス範囲や使用状況を示します。
LOCKS
LOCKSセクションは、javaプロセス内部の同期処理に使われているロックとその所有状況の一覧を含んでいます。
THREADS
THREADSセクションは、ダンプ生成時にjavaプロセス内に存在していたスレッドの一覧を示します。ここで言うスレッドはOSレベルのスレッドを指していて、Javaのスレッドに対応しているOSスレッド以外に、JITコンパイラやGCが使用するOSスレッドも含まれます。
"Current thread"として最初に表示されるのがダンプ生成時に実行中だったスレッドで、シグナルやJava例外の発生の原因としてまず最初に注目することになります。
Javaスレッドの場合はJavaのコールスタックが表示されるので、ダンプ生成時にどのメソッドがどのメソッドを呼んでいたのかが分かります。
デッドロックしていた場合には、前項のLOCKSの内容と合わせて、どのスレッドがどの資源を取り合っていたのかを確認します。
HOOKS
HOOKSセクションには、登録されていたフック関数の情報が含まれています。
SHARED CLASSES
SHARED CLASSESセクションには、OpenJ9の共有クラスキャッシュの情報が含まれます。共有キャッシュ内に保存されているJavaクラスやAOTメソッドの数などが分かります。
CLASSES
CLASSESセクションには、Javaのクラスローダーと、各クラスローダーがロードしたクラスとそのアドレス、共有状態の一覧が含まれています。
coreファイル
二つ目のファイルはcoreです。core.<日付>.<時刻>.<プロセスID>.<連番>.dmpのようなファイル名になります。
OSの設定によってはcoreファイルは生成されないため、診断に使う場合は設定を変更する必要があります。
coreファイルには異常発生時のjavaプロセスのメモリーイメージが含まれていて、異常発生時にプロセス内でどんなスレッドが走っていたか、Javaヒープやスレッドのスタックのメモリーはどのような状態だったか、実行中だったCPU命令列がどのようなものだったかなどを調べることができます。
coreファイルの内容を調べるには、OS標準のデバッガ (Linuxならgdb、macOSならlldbなど) や、Semeru Runtimesに含まれるjdmpviewコマンドを使います。具体的にどのように使うかは本稿では割愛します。
heapdumpファイル
三つ目のファイルはheapdumpです。heapdump.<日付>.<時刻>.<プロセスID>.<連番>.phdのようなファイル名になります。
ダンプ生成時のJavaヒープの内容を記録したもので、OutOfMemoryErrorが発生した場合などに、Eclipse Memory Analyzer (MAT)のようなツールを使って調べることができます。
jitdumpファイル
四つ目のファイルはjitdumpです。jitdump.<日付>.<時刻>.<プロセスID>.<連番>.dmpのようなファイル名になります。
これは、javaプロセスが異常終了した場合に関係していそうなメソッドをJITコンパイルしたトレースファイルです。1ファイル内に複数メソッドのトレースを含む場合があります。
JITコンパイラーの開発者がデバッグのために使います。読み方は本稿では触れません。
Snapファイル
五つ目のファイルはjitdumpです。Snap.<日付>.<時刻>.<プロセスID>.<連番>.trcのようなファイル名になります。
このファイルはJVM内のどのトレースポイントを通過したかを示すトレースファイルです。バイナリーファイルなので、Semeru Runtimesに含まれるtraceformatというツールを使って読める形式に変換します。
-Xdumpオプション
これらの診断用ファイルの生成は-Xdumpオプションを使ってコントロールできます。
指定できる項目が多くて複雑なのですが、Xdump Option Builderというウェブページを使うと-Xdumpのサブオプションを組み立てることができます。
たとえば、「JavaのFileNotFoundExceptionが発生したときにjavacoreファイルを生成させてjavaプロセスを終了させる」みたいなことを-Xdumpで指定できます。
どのようなダンプエージェントが登録されているかは-Xdump:whatオプションで知ることができます。
$ java -Xdump:what -version
Registered dump agents
----------------------
-Xdump:system:
events=gpf+abort+traceassert+corruptcache,
file=/home/ubuntu/core.%Y%m%d.%H%M%S.%pid.%seq.dmp,
range=1..0,
priority=999,
request=serial
----------------------
-Xdump:system:
events=systhrow,
filter=java/lang/OutOfMemoryError,
(以下略)
診断用ファイルは基本的にjavaプロセスのカレントディレクトリに生成されます。別のディレクトリを指定したい場合には-Xdump:directory=<path>オプションで指定します。
まとめ
Semeru Runtimes/OpenJ9が生成する診断用ファイルについて簡単に説明しました。
基本的にはOpenJ9の開発者が問題の解析用に使うものですが、Javaアプリケーションの開発者もデッドロックやメモリーリークの調査などに使える場合があります。