モニターのアドレスを取得する簡単な方法はないと思います。jstackがそれを行う方法は次のとおりです
import com.sun.tools.attach.VirtualMachine;
import sun.tools.attach.HotSpotVirtualMachine;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
public class Main {
public static void main(String[] args) throws Exception {
VirtualMachine vm = VirtualMachine.attach(getPid());
HotSpotVirtualMachine hsvm = (HotSpotVirtualMachine) vm;
InputStream in = hsvm.remoteDataDump("-l");
byte b[] = new byte[256];
int n;
do {
n = in.read(b);
if (n > 0) {
String s = new String(b, 0, n, "UTF-8");
System.out.print(s);
}
} while (n > 0);
in.close();
}
private static String getPid() {
String name = ManagementFactory.getRuntimeMXBean().getName();
int ind = name.indexOf('@');
return name.substring(0, ind);
}
}
このスニペットを実行するには、忘れずに$JDK_HOME/lib/tools.jar
クラスパスに追加してください。
2012-10-31 08:48:08 完全なスレッド ダンプ Java HotSpot(TM) 64 ビット サーバー VM (20.5-b03 混合モード) が生成する出力は次のとおりです。
"Monitor Ctrl-Break" daemon prio=6 tid=0x0000000006b98000 nid=0x1d70 runnable [0x00000000074df000]
java.lang.Thread.State: RUNNABLE
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
- locked <0x00000007d5d53148> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:462)
at java.net.ServerSocket.accept(ServerSocket.java:430)
at com.intellij.rt.execution.application.AppMain$1.run(AppMain.java:82)
at java.lang.Thread.run(Thread.java:662)
Locked ownable synchronizers:
- None
...
hsvm.remoteDataDump("-l")
何ができるかを詳しく見てみましょう
...
public InputStream remoteDataDump(Object ... args) throws IOException {
return executeCommand("threaddump", args);
}
/*
* Execute the given command in the target VM - specific platform
* implementation must implement this.
*/
abstract InputStream execute(String cmd, Object ... args)
throws AgentLoadException, IOException;
/*
* Convenience method for simple commands
*/
private InputStream executeCommand(String cmd, Object ... args) throws IOException {
try {
return execute(cmd, args);
} catch (AgentLoadException x) {
throw new InternalError("Should not get here");
}
}
...
これは、Windows 用の execute メソッドの実装です ( で見つけることができますsun.tools.attach.WindowsVirtualMachine
) 。
InputStream execute(String cmd, Object ... args)
throws AgentLoadException, IOException {
assert args.length <= 3; // includes null
// create a pipe using a random name
int r = (new Random()).nextInt();
String pipename = "\\\\.\\pipe\\javatool" + r;
long hPipe = createPipe(pipename);
// check if we are detached - in theory it's possible that detach is invoked
// after this check but before we enqueue the command.
if (hProcess == -1) {
closePipe(hPipe);
throw new IOException("Detached from target VM");
}
try {
// enqueue the command to the process
enqueue(hProcess, stub, cmd, pipename, args);
// wait for command to complete - process will connect with the
// completion status
connectPipe(hPipe);
// create an input stream for the pipe
PipedInputStream is = new PipedInputStream(hPipe);
// read completion status
int status = readInt(is);
if (status != 0) {
// special case the load command so that the right exception is thrown
if (cmd.equals("load")) {
throw new AgentLoadException("Failed to load agent library");
} else {
throw new IOException("Command failed in target VM");
}
}
// return the input stream
return is;
} catch (IOException ioe) {
closePipe(hPipe);
throw ioe;
}
}
static native void init();
static native byte[] generateStub();
static native long openProcess(int pid) throws IOException;
static native void closeProcess(long hProcess) throws IOException;
static native long createPipe(String name) throws IOException;
static native void closePipe(long hPipe) throws IOException;
static native void connectPipe(long hPipe) throws IOException;
static native int readPipe(long hPipe, byte buf[], int off, int buflen) throws IOException;
static native void enqueue(long hProcess, byte[] stub,
String cmd, String pipename, Object ... args) throws IOException;
したがって、基本的に名前付きパイプが開かれ、いくつかのコマンドがその上で実行され、すべての魔法はネイティブコードの中にありますhotspot/src/share/vm/services/attachListener.cpp
// Implementation of "threaddump" command - essentially a remote ctrl-break
//
static jint thread_dump(AttachOperation* op, outputStream* out) {
bool print_concurrent_locks = false;
if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) {
print_concurrent_locks = true;
}
// thread stacks
VM_PrintThreads op1(out, print_concurrent_locks);
VMThread::execute(&op1);
// JNI global handles
VM_PrintJNI op2(out);
VMThread::execute(&op2);
// Deadlock detection
VM_FindDeadlocks op3(out);
VMThread::execute(&op3);
return JNI_OK;
}
一般的に言えば、モニターを取得したオブジェクトのアドレスを抽出したい場合は、最初のスニペットの出力を解析し、スレッド ID などによって必要なフラグメントを抽出できます。
その他のオプションは、デバッグ モードでプロセスにアタッチし、デバッガー API または JNI を使用することです。