プロセス情報について
とりあえず、ここまでで class
ファイルの中身や作り方とかjavaがそれをどう認識して読み込むのかの概要は把握出来たつもりです。
次はJavaのプロセス情報などがどこにあるのか?という疑問について調査します。
具体的には、jps
コマンドを実行すると今JVMを使っているプログラムに関する情報が ps
コマンドのように表示できますが、これを実現している仕組みについて把握することを目指します。
ソースを読むのが早いと考えたので、jps
のソースを読んでみることにします。
jpsの処理の流れは、
- 起動しているVMの情報をmonitoredHostから取得する
Set<Integer> jvms
はvmのid(lvmid)が入っているので、順番に処理していく- idとmonitoredHostを使ってvmの情報を出力する
という形になっています。
自分が一番興味があったのは、1から2の起動しているVMの情報が何処からくるのか?というあたりなので関係しそうなところを読んでみます。
VMの情報や起動中のvmのidを取得するまでの流れ
- 引数からhostIdentifierを作成(とりあえず)する
hostname = args[args.length - 1]
などとなっているので、それが利用されるようだ。リモートなJVMなども想定されているのだろう
- 実際は、nullが渡されて、以下の処理で”//localhost”になることが多そうです
- MonitoredHostというオブジェクトを取得していきます
- https://github.com/openjdk/jdk/blob/50d47de8358e2f22bf3a4a165d660c25ef6eacbc/src/jdk.jcmd/share/classes/sun/tools/jps/Jps.java#L58
- 実際の取得処理
- https://github.com/openjdk/jdk/blob/9629627e2c8021c254517ac5463cc66723175fd9/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHost.java#L153
- https://github.com/openjdk/jdk/blob/9629627e2c8021c254517ac5463cc66723175fd9/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHost.java#L197
- MonitoredHostServiceというサービスから実際のMonitoredHostを取得する
- https://github.com/openjdk/jdk/blob/9629627e2c8021c254517ac5463cc66723175fd9/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHostService.java
- ServiceLoaderとmodule-infoからMonitorHostServiceは複数インスタンス化されている
- ServiceLoader.load() を実施しているのはここ
- https://github.com/openjdk/jdk/blob/9629627e2c8021c254517ac5463cc66723175fd9/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredHost.java#L140
- module-infoで候補が決まっていそうです
- https://github.com/openjdk/jdk/blob/9629627e2c8021c254517ac5463cc66723175fd9/src/jdk.internal.jvmstat/share/classes/module-info.java#L46
MonitoredHostLocalService
が最終的に- このMonitoredHostProviderを返すことになりそうです
- MonitoredHostからactiveVMを取得する
- https://github.com/openjdk/jdk/blob/739769c8fc4b496f08a92225a12d07414537b6c0/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/MonitoredHostProvider.java#L149
- LocalVmManagerがPerfDataFileを読みこんでいそうです
- https://github.com/openjdk/jdk/blob/93692ea0a9bc437309b808f511c771a79dcdfb9a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/LocalVmManager.java
"/tmp"
の下にある、"hsperfdata_\\S*"
というデータを読むようですね
各種データの読み出し
以降の処理は、MonitoredVmUtil
を使って色々情報を取ってくるような形になっています。
https://github.com/openjdk/jdk/blob/9629627e2c8021c254517ac5463cc66723175fd9/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor/MonitoredVmUtil.java#L64
findbyNameが情報を取ってくる先は、先ほどのhsperfdataになっています。
というわけで、hsperfdataを見てJpsは色々表示してくれているようですね。
確認してみる
実際に、Javaのプロセスを起動してみて、/tmp
の下に該当ファイルが出来ているかを確認してみましょう。
$ jps
158498 Jps
158132 main
158345 main
さて、/tmp
の下を除いてみましょう
$ ls -l
hsperfdata_sakura/ ......
$ ls -l /tmp/hsperfdata_sakura
合計 64K
-rw------- 1 sakura sakura 32768 8月 1 18:32 158132
-rw------- 1 sakura sakura 32768 8月 1 18:32 158345
おぉぉ。たしかにここのファイルが存在しているようです。
Jpsの結果にはJps自体も含まれているので終了時に削除されているので、Jpsの結果と完全に一致していると言えそうですね。
長年の謎の1つは解消出来た気がしました。でもまだまだ分かってないことが多すぎるので続きます。
次回はJNI周りについて調べたいと思います。
余談
上のソースコードのうち、/tmp
の位置を取得するコードはJavaとしては以下のようなJNIを利用したCの関数への呼び出しになっているようですね。
対応するCのソースコードとしては、jdk/src/hotspot/share/prims/jvm.cpp
の JVM_GetTemporaryDirectory
関数が呼びだされています。
最終的に os::get_temp_directory()
が呼ばれています。自分の環境は、linuxなので jdk/src/hotspot/os/linux/os_linux.cpp
の中に実装がありました。/tmp
完全に決め打ちとなっているようです。