独自のプロファイラーを構築し、JVMTI API を使用してネイティブ ライブラリ エージェントを構築します。このエージェントは、追加パラメーター -agentlib を使用して、JVM と一緒に開始できます。さらに、実行中の JVM にエージェントを挿入できるAttach API があります。次のコードを使用して、この機能をプロファイラーに実装したいと考えました。
try {
String pid = VirtualMachine.list().get(0).id();
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgentLibrary("agent");
} catch (AgentLoadException e1) {
e1.printStackTrace();
} catch (AgentInitializationException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (AttachNotSupportedException e) {
e.printStackTrace();
}
それは何をするためのものか?利用可能な実行中のすべての仮想マシン ( VirtualMachine.list()
) から最初の仮想マシンを選択し、それにアタッチしてエージェントをロードしようとします。libagent.so という名前の UNIX システム上のエージェントは見つかりますが、エージェントをロードしようとすると、次の例外がスローされます。
com.sun.tools.attach.AttachNotSupportedException:
Unable to open socket file:
target process not responding or HotSpot VM not loaded.
ソース コードを調べると、という名前のファイルが見つからないため、この例外がスローされます.java_pid<pid>
。ドキュメントには、この種のファイルに関する多くの情報が見つかりませんでした。この種のファイルはもう使われていないとよく耳にしますが、私は Java 1.6 を実行しています。
また、他の JVM にアタッチしようとしました。実際、このアタッチ プロセスを動的に保ちました。テスト上の理由から、任意の JVM にアタッチしようとしました。
これは、 sun.tools.attach: LinuxVirtualMachine.javaから取られた、例外につながるコードです:
// Return the socket file for the given process.
// Checks working directory of process for .java_pid<pid>. If not
// found it looks in /tmp.
private String findSocketFile(int pid) {
// First check for a .java_pid<pid> file in the working directory
// of the target process
String fn = ".java_pid" + pid;
String path = "/proc/" + pid + "/cwd/" + fn;
File f = new File(path);
if (!f.exists()) {
// Not found, so try /tmp
path = "/tmp/" + fn;
f = new File(path);
if (!f.exists()) {
return null; // not found
}
}
return path;
}
それは、ルートから/proc/<pid>
ディレクトリを探していると言います。JDK7 の変更セットを見ると、コードJDK7 Changeset to LinuxVirtualMachine に変更を加えているようです。