Ich denke, es gibt keine einfache Möglichkeit, eine Adresse eines Monitors zu erhalten. Hier ist, wie jstack tut es
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);
}
}
dieses Snippet laufen nicht vergessen $JDK_HOME/lib/tools.jar
zum Classpath hinzufügen. Hier
ist die Ausgabe, die es 2012-10-31 08.48.08 Voll Thread-Dump Java HotSpot (TM) 64-Bit Server VM (20.5-b03 Mischbetrieb) erzeugt:
"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
...
schauen wir uns näher an, was hsvm.remoteDataDump("-l")
tut
...
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");
}
}
...
und hier ist eine Implementierung der Methode execute für Fenster (Sie es in sun.tools.attach.WindowsVirtualMachine
finden)
Also im Grunde die Named Pipe geöffnet und einige Befehle ausgeführt werden über sie und die ganze Magie in dem nativen Code ist in 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;
}
Im Allgemeinen, wenn Sie möchten, dass die Adresse des Objekts extrahieren Wenn Sie den Monitor von erhalten haben, können Sie die Ausgabe des allerersten Snippets parsen und das erforderliche Fragment z. B. nach der Thread-ID extrahieren.
Weitere Optionen werden im Debug-Modus an Ihren Prozess angehängt und verwenden Debugger API oder JNI.
Nein, das ist nicht meine Frage. Die Frage ist, dass ich einen Prozess habe, bei dem Deadlocks alle 100.000 Iterationen in der Produktion sagen, und ich würde gerne herausfinden, welche Objekte tatsächlich in den Deadlock involviert waren, vielleicht durch das Protokollieren von Monitoradressen an einem bestimmten Punkt. Ändern Sie das Design, um nur eine einzige Sperre für jede Operation zu erfordern? lol. – BeeOnRope
Keine einzige Sperre für alle Operationen, sondern eine einzige Sperre für jede einzelne Operation. Ich denke, ein Code-Review würde tatsächlich das Problem finden. Das hört sich genau so an, wie ich es gerade beschrieben habe. – Zagrev
-1 für nicht die Jungs Frage zu lesen! – Toby