2012-10-30 5 views
5

Wenn Sie den Stack-Dump eines Prozesses erhalten, z. B. über Jstack, erhalten Sie Informationen über gesperrte Monitore (und Synchronizer) mit jeweils einer Adresse. Zum Beispiel von einem trivialen Deadlocks Zweifaden Prozess (mit jstack):Programmatische Möglichkeit, die Adresse für Java-Monitore in einem Stack-Dump anzuzeigen?

"Thread-0" prio=10 tid=0x00007f1444042000 nid=0x2818 waiting for monitor entry [0x00007f14433ca000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at scrap.DeadlockTest$Deadlocker.run(DeadlockTest.java:49) 
    - waiting to lock <0x00000007c14e6378> (a java.lang.Object) 
    - locked <0x00000007c14e6368> (a java.lang.Object) 
    at java.lang.Thread.run(Thread.java:619) 

... (omitted some lines here) 

Java stack information for the threads listed above: 
=================================================== 
"Thread-1": 
    at scrap.DeadlockTest$Deadlocker.run(DeadlockTest.java:49) 
    - waiting to lock <0x00000007c14e6368> (a java.lang.Object) 
    - locked <0x00000007c14e6378> (a java.lang.Object) 
    at java.lang.Thread.run(Thread.java:619) 
"Thread-0": 
    at scrap.DeadlockTest$Deadlocker.run(DeadlockTest.java:49) 
    - waiting to lock <0x00000007c14e6378> (a java.lang.Object) 
    - locked <0x00000007c14e6368> (a java.lang.Object) 
    at java.lang.Thread.run(Thread.java:619) 

Gibt es eine Möglichkeit, in dem Java-Code zur Laufzeit zu bekommen, die gleichen Adressen oben, wie 0x00000007c14e6368 gezeigt?

Ich habe versucht, die Identität Hash-Code für die Objekte unter Verwendung des Monitor zu entsprechen, sowie MonitorInfo über ThreadMXBean, ohne Glück (die Werte entsprechen nicht, zumindest auf 64-Bit-Java).

Antwort

-2

Also, Ihre Frage ist eigentlich, gibt es eine Möglichkeit zu bestimmen, welche zwei Objekte in einem Programm festgefahren sind? Dieses triviale Beispiel zeigt einen Weg, um nach einem Deadlock zu suchen. Eine der häufigsten Ursachen für Deadlock ist das Abrufen mehrerer Sperren, jedoch in zwei verschiedenen Ordnungen. Suchen Sie also den Code, in dem er gesperrt ist, um sicherzustellen, dass Sie die Sperren immer in der gleichen Reihenfolge anfordern.

Die Tatsache, dass Sie mehrere Sperren benötigen, um eine Operation auszuführen, bedeutet, dass Sie das Design ändern sollten, um nur eine einzige Sperre für jede Operation zu erfordern.

+0

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

+0

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

+0

-1 für nicht die Jungs Frage zu lesen! – Toby

3

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.

0

Vielleicht können Sie das Objekt protokollieren, das eine Sperre anfordert. Dann würdest du wissen, wer zum Zeitpunkt des Deadlocks das Schloss hat.

Verwandte Themen