Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

Serviceability Agentをjhsdbから読み進めてみる

Serviceability Agentやjhsdbについては、OpenJDK Reviewerの末永さんのスライドが大変参考になります。

www.slideshare.net

JDK 8まで、HSDB (CLHSDB)を使うにはjavaコマンドで実行しました。

$ java -Dsun.jvm.hotspot.degugger.useProcDebugger=true -classpath $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB

JDK 9からjhsdbというランチャーが入ったので、簡単に呼び出せます。

$ jhsdb hsdb

f:id:jyukutyo:20180223152756p:plain

HSDBが立ち上がりました。HSDB自体の話は今回の範囲外ですが、コアファイルを読み込ませて解析するデバッガです。

このjhsdbは、ややこしいのですがHSDBだけのものではありません。

$ jhsdb
    clhsdb          command line debugger
    debugd          debug server
    hsdb            ui debugger
    jstack --help   to get more information
    jmap   --help   to get more information
    jinfo  --help   to get more information
    jsnap  --help   to get more information

jstackやjmapなども呼び出せます。

jhsdbはバイナリファイルですが、文字列を読んでみます。

$ strings $JAVA_HOME/bin/jhsdb
JDK_JAVA_OPTIONS
_JAVA_LAUNCHER_DEBUG
_JAVA_OPTIONS
NOTE: Picked up %s: %s
9+181
java
jhsdb
-J-ms8m
jdk.hotspot.agent/sun.jvm.hotspot.SALauncher
...

SALauncherというクラスを読んでいます。このSAというのはServiceability Agentの略です。ネイティブデバッガ同様の仕組みでプロセスから情報収集できる(上記スライドより)とのことです。

OpenJDKをダウンロードすると、SALauncherクラスがあります。

...
public class SALauncher {
...
    public static void main(String[] args) {
        // Provide a help
        if (args.length == 0) {
            launcherHelp();
            return;
        }
...
    }
...
}

mainメソッドがあります。これが呼び出されているのでしょう。先ほどjhsdbと引数なしで実行しました。launcherHelp()を見てみます。

    private static boolean launcherHelp() {
        System.out.println("    clhsdb       \tcommand line debugger");
        System.out.println("    debugd       \tdebug server");
        System.out.println("    hsdb         \tui debugger");
        System.out.println("    jstack --help\tto get more information");
        System.out.println("    jmap   --help\tto get more information");
        System.out.println("    jinfo  --help\tto get more information");
        System.out.println("    jsnap  --help\tto get more information");
        return false;
    }

まさに出力に合致するコードです。単にSystem.out.println()しているだけなんですね。

あとは引数で指定したツールを実行するというコードでした。

            // Run SA interactive mode
            if (args[0].equals("clhsdb")) {
                runCLHSDB(oldArgs);
                return;
            }

            if (args[0].equals("hsdb")) {
                runHSDB(oldArgs);
                return;
            }

            // Run SA tmtools mode
            if (args[0].equals("jstack")) {
                runJSTACK(oldArgs);
                return;
            }

            if (args[0].equals("jmap")) {
                runJMAP(oldArgs);
                return;
            }

            if (args[0].equals("jinfo")) {
                runJINFO(oldArgs);
                return;
            }

            if (args[0].equals("jsnap")) {
                runJSNAP(oldArgs);
                return;
            }

            if (args[0].equals("debugd")) {
                runDEBUGD(oldArgs);
                return;
            }

このモジュール内にHSDB.javaやCLHSDB.java、JSnap.javaなどがあるので、ここからツールをどれか読み進めます。