2012-10-30 13 views
5

यदि आपको किसी प्रक्रिया का स्टैक डंप मिलता है, उदाहरण के लिए, जेस्टैक के माध्यम से, आपको प्रत्येक के लिए पते के साथ लॉक मॉनीटर (और सिंक्रनाइज़र्स) के बारे में जानकारी मिलती है। (Jstack का प्रयोग करके) जैसे, एक तुच्छता से गतिरोध दो धागा प्रक्रिया से:एक स्टैक डंप में जावा मॉनीटर के लिए दिखाए गए पते को पाने का प्रोग्रामेटिक तरीका?

"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) 

वहाँ किसी भी तरह से जावा कोड में रनटाइम पर, प्राप्त करने के लिए है, एक ही पते को इस तरह के 0x00000007c14e6368 के रूप में ऊपर दिखाए गए,?

मैंने मॉनिटर के साथ-साथ के माध्यम से ThreadMXBean के माध्यम से के माध्यम से किसी भी भाग्य के साथ पहचान हैश कोड का उपयोग करने का प्रयास किया है (मान कम से कम 64-बिट जावा पर नहीं हैं)।

उत्तर

-2

तो, आपका प्रश्न वास्तव में है, क्या यह निर्धारित करने का कोई तरीका है कि किसी प्रोग्राम में कौन सी दो वस्तुएं मारे गए हैं? यह मामूली उदाहरण वास्तव में डेडलॉक की जांच करने का एक तरीका बताता है। डेडलॉक के सबसे आम कारणों में से एक एकाधिक ताले को पुनः प्राप्त कर रहा है, लेकिन दो अलग-अलग ऑर्डर में। तो, उस कोड को खोजें जहां यह ताला लगा है कि आप हमेशा एक ही क्रम में ताले का अनुरोध कर रहे हैं।

एक तरफ, तथ्य यह है कि आपको कुछ ऑपरेशन करने के लिए कई ताले की आवश्यकता होती है, इसका मतलब है कि आपको डिज़ाइन को बदलना चाहिए ताकि किसी भी ऑपरेशन के लिए केवल एक लॉक की आवश्यकता हो।

+0

नहीं, यह मेरा प्रश्न नहीं है। सवाल यह है कि मेरे पास एक प्रक्रिया है जो डेडलॉक्स उत्पादन में हर 100,000 पुनरावृत्तियों का कहना है, और मैं यह जानना चाहता हूं कि डेडलॉक में वास्तव में कौन सी वस्तुएं शामिल थीं, शायद किसी बिंदु पर मॉनिटर पते लॉग इन करके। किसी भी ऑपरेशन के लिए केवल एक लॉक की आवश्यकता के लिए डिज़ाइन बदलें? जबरदस्त हंसी। – BeeOnRope

+0

सभी परिचालनों के लिए एक एकल लॉक नहीं है, लेकिन किसी एकल ऑपरेशन के लिए एक लॉक है। मुझे लगता है कि एक कोड समीक्षा वास्तव में समस्या मिल जाएगी। यह ठीक वैसे ही लगता है जो मैंने अभी वर्णित किया है। – Zagrev

+0

-1 लोगों को प्रश्न पढ़ने के लिए नहीं! – Toby

3

मुझे लगता है कि मॉनिटर का पता पाने का कोई आसान तरीका नहीं है। यहाँ कैसे 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); 
    } 

} 

करता है इस स्निपेट को चलाने के लिए classpath को $JDK_HOME/lib/tools.jar जोड़ने के लिए मत भूलना है।

"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 

... 

:

यहाँ उत्पादन यह 2012-10-31 08:48:08 पूर्ण धागा डंप जावा हॉटस्पॉट (टीएम) 64-बिट सर्वर वी एम (20.5-B03 मिश्रित मोड) का उत्पादन होता है मैदान पर करीब नजर डालते हैं क्या 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"); 
    } 
} 
... 

करता है और यहाँ खिड़कियों के लिए निष्पादित विधि के एक कार्यान्वयन है (यदि आप इसे 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; 
} 

में मूल कोड में है सामान्यतया आप वस्तु का पता निकालने के लिए करना चाहते हैं आपने मॉनिटर प्राप्त कर लिया है, आप पहले स्निपेट के आउटपुट को पार्स कर सकते हैं और आवश्यक टुकड़े निकाल सकते हैं, उदाहरण के लिए, थ्रेड आईडी द्वारा।

अन्य विकल्प डीबग मोड में और डीबगर एपीआई या जेएनआई का उपयोग करके आपकी प्रक्रिया को जोड़ रहे हैं।

0

शायद आप उस ऑब्जेक्ट को लॉग कर सकते हैं जो लॉक का अनुरोध करता है। तब आप जान लेंगे कि डेडलॉक के समय लॉक कौन है।

संबंधित मुद्दे

 संबंधित मुद्दे