結論
VM起動引数として指定された-XX:StartFlightRecording=xxx=xxx,yyy=yyy
という形式のパラメータは、VMを起動する途中で、JFRのパラメータを初期化するメソッド(JfrOptionSet::initialize
)でjcmd
の方法に変換されます。その後、VMはJFRのパラメータを設定するメソッド(JfrOptionSet::configure
)で内部的に jcmd JFR.configure
を実行することで設定を適用します。
VMを起動する処理
VMを起動する処理の一部としてjdk/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp
にあるon_create_vm_2
メソッドが実行されます。
この処理では、主に以下の処理が実行されます。
- JFRのパラメータを初期化
JfrOptionSet::initialize
- 設定
JfrOptionSet::configure
VM を作成する処理の一部
bool JfrRecorder::on_create_vm_2() { (略) Thread* const thread = Thread::current(); if (!JfrOptionSet::initialize(thread)) { return false; } if (!register_jfr_dcmds()) { return false; } (略) if (!validate_recording_options(thread)) { return false; } if (!JfrOptionSet::configure(thread)) { return false; } (略) }
1. JFR のパラメータを初期化
この処理では、主に以下の処理が実行されます。
- デフォルト値の読み込み
- VM起動引数を
jcmd
の形式に変換 - 過去の形式の古いパラメータ(
ObsoleteOption
)が使われていたらメッセージを出力
bool JfrOptionSet::initialize(Thread* thread) { register_parser_options(); if (!parse_flight_recorder_options_internal(thread)) { return false; } (略) }
2. 設定
jcmd
を使って設定します。jcmd JFR.configure
の実体であるJfrConfigureFlightRecorderDCmd
クラスのインスタンスに入力されたパラメータを指定して内部的にコマンドを実行(execute
)します。
bool JfrOptionSet::configure(TRAPS) { (略) // delegate to DCmd execution JfrConfigureFlightRecorderDCmd configure(&st, false); (略) configure._stack_depth.set_is_set(_dcmd_stackdepth.is_set()); configure._stack_depth.set_value(_dcmd_stackdepth.value()); (略) configure.set_verbose(false); configure.execute(DCmd_Source_Internal, THREAD); (略) }
どこに設定は格納されているのか?
設定は Java と C/C++ の範囲でそれぞれ格納されています。Java は jdk.jfr
モジュールのjdk/jfr/internal/Options
クラス、C/C++ はhotspot/share/jfr/recorder/jfrRecorder.cpp
に格納されます。
jcmd JFR.configure
では Options
クラスに格納します。Options
クラスでは setter で自分の持つフィールドに格納すると共に、JNI で C/++ のメソッドを呼び出して jfrRecorder
にも格納します。
Options
で設定を変更するメソッド
public static synchronized void setGlobalBufferCount(long globalBufCount) { jvm.setGlobalBufferCount(globalBufCount); globalBufferCount = globalBufCount; }
jfrRecorder.cpp
でC/C++ で設定値が格納される変数
jlong JfrOptionSet::_max_chunk_size = 0; jlong JfrOptionSet::_global_buffer_size = 0; jlong JfrOptionSet::_thread_buffer_size = 0; jlong JfrOptionSet::_memory_size = 0; jlong JfrOptionSet::_num_global_buffers = 0; jlong JfrOptionSet::_old_object_queue_size = 0; u4 JfrOptionSet::_stack_depth = STACK_DEPTH_DEFAULT; jboolean JfrOptionSet::_sample_threads = JNI_TRUE; jboolean JfrOptionSet::_retransform = JNI_TRUE;
JNIのマッピングは hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp
とhotspot/share/jfr/jni/jfrJniMethod.cpp
で行われてます。