2017-03-19 23 views
0

當前我試圖通過JDI提取一些執行數據。 因此我第一手動啓動Java虛擬機與所述命令JDI ThreadReference.frame()導致IncompatibleThreadStateException

java -agentlib:jdwp=transport=dt_socket,server=y,address=8000 DebugDummy 

我DebugDummy.java:

public class DebugDummy { 

    public class MyInnerClass { 
     private int a; 

     public MyInnerClass(int a) { 
      this.a = a; 
      this.doSomething(); 
     } 

     public void doSomething() { 
      System.out.println(this.a); 
     } 
    } 

    public DebugDummy() { 
     MyInnerClass myInnerClass = new MyInnerClass(5); 
     myInnerClass.doSomething(); 
    } 

    public static void main(String[] args) { 
     DebugDummy dd = new DebugDummy(); 
    } 
} 

然後與JDI連接,等待每一行的主方法進入和步驟線通過代碼執行。

public class VMStart { 

public static void main(String[] args) { 

    //Check for argument count 
    if(args.length != 3){ 
     System.err.println("Not enough parameter!"); 
     System.exit(0); 
    } 

    String cwd = "", mainClass = "", vmPort = ""; 

    cwd = args[0]; 
    mainClass = args[1]; 
    vmPort = args[2]; 

    System.out.println("CWD: " + cwd); 
    System.out.println("MainClass: " + mainClass); 
    System.out.println("VM Port: " + vmPort); 

    //Init vm arguments and settings 
    VirtualMachineManager vmm = Bootstrap.virtualMachineManager(); 
    AttachingConnector ac = vmm.attachingConnectors().get(0); 

    //Setting port 
    Map<String, Connector.Argument> env = ac.defaultArguments(); 
    Connector.Argument port = env.get("port"); 
    port.setValue(vmPort); 

    //Setting hostname 
    Connector.Argument hostname = env.get("hostname"); 
    hostname.setValue("localhost"); 

    //Attach vm to remote vm 
    VirtualMachine vm = null; 
    try { 
     vm = ac.attach(env); 
    } catch (IOException | IllegalConnectorArgumentsException e) { 
     //Doesn't work, stop here... 
     System.err.println("Can't connect to vm!"); 
     e.printStackTrace(); 
     System.exit(0); 
    } 

    //Create EventQueue and EventRequestManager for further event handling 
    EventQueue eventQueue = vm.eventQueue(); 
    EventRequestManager mgr = vm.eventRequestManager(); 

    //Set the vm to sleep for further operations 
    vm.suspend(); 

    //Searching for our main thread reference 
    ThreadReference mainThread = null; 
    List<ThreadReference> threads = vm.allThreads(); 
    for (ThreadReference thread : threads) { 
     if ("main".equals(thread.name())) { 
      mainThread = thread; 
     } 
    } 

    //Create and register MethodEntryRequest, so we can pause execution at first line of main later on 
    MethodEntryRequest methodEntryRequest = mgr.createMethodEntryRequest(); 
    methodEntryRequest.addClassFilter(mainClass); 
    methodEntryRequest.addThreadFilter(mainThread); 
    methodEntryRequest.enable(); 

    //Resume the execution of the remote vm 
    vm.resume(); 

    //Resume the execution of the main thread in remote vm 
    mainThread.resume(); 

    //Waiting for our needed MethodEntryEvent so execution started at first line of main method 
    Event event = null; 
    while (true) { 
     EventSet eventSet = null; 
     try { 
      eventSet = eventQueue.remove(); 
     } catch (InterruptedException e) { 
      System.err.println("Something went wrong while waiting for MethodEntryEvent"); 
      e.printStackTrace(); 
      System.exit(0); 
     } 
     event = eventSet.eventIterator().next(); 
     if (event instanceof MethodEntryEvent) { 
      break; 
     } 
    } 

    //Indicates whether there is still code execution in our remote vm 
    boolean codeIsExecuting = true; 

    //Step loop until there is no code execution 
    while(codeIsExecuting){ 
     //Filter for steeping not into java api methods 
     final String[] noBreakpointRequests = {"java.*", "javax.*", "sun.*", "com.sun.*"}; 

     //Creating our StepRequest for each line of code 
     StepRequest stepRequest = mgr.createStepRequest(mainThread, StepRequest.STEP_LINE, StepRequest.STEP_INTO); 
     for(String classInFilter : noBreakpointRequests){ //Apply filter 
      stepRequest.addClassExclusionFilter(classInFilter); 
     } 
     stepRequest.addCountFilter(1); 
     try{ 
      stepRequest.enable(); 
     }catch(IllegalThreadStateException e){ 
      //program reached end of code, so there is no code execution anymore 
      codeIsExecuting = false; 
      System.out.println("Code execution ended..."); 
      break; 
     } 

     //Extract data from current vm execution state 
     //TODO 
     System.out.println("TODO - extract data from current vm execution state"); 

     //Test 
     StackFrame stackFrame = null; 
     try { 
      stackFrame = mainThread.frame(0); 
      System.out.println(stackFrame.location()); 
     } catch (IncompatibleThreadStateException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     //Resume vm for code execution 
     vm.resume(); 

     try { 
      Thread.sleep(10L); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

     //StepRequest is done, remove it from event queue to prevent lock 
     mgr.deleteEventRequest(stepRequest); 
    } 

    //Debugging has ended, we free our remote vm 
    try{ 
     vm.dispose(); 
    }catch(VMDisconnectedException e){ 

    } 

    //Print results 
    //TODO 
    System.out.println("TODO - print results..."); 

} 
} 

Unfortunally,如果我刪除了Thread.sleep()方法,我在行得到一個IncompatibleThreadStateException

stackFrame = mainThread.frame(0); 

例外:

com.sun.jdi.IncompatibleThreadStateException at com.sun.tools.jdi.ThreadReferenceImpl.privateFrames(ThreadReferenceImpl.java:436) 
at com.sun.tools.jdi.ThreadReferenceImpl.frame(ThreadReferenceImpl.java:355) 
at VMStart.main(VMStart.java:143) 

有什麼不對?在繼續進一行之前,我是否必須等待某個事件?

回答

0

最後,我找到了解決自己...

此代碼已經被插入vm.resume()指令後:

boolean go = false; 
while (!go) { 
    EventSet eventSet = null; 
    try { 
     eventSet = eventQueue.remove(); 
    } catch (InterruptedException e) { 
     System.err.println("Something went wrong while waiting for StepEvent"); 
     e.printStackTrace(); 
     System.exit(0); 
    } 
    for (Event e : eventSet) { 
     if (e instanceof StepEvent) { 
      System.out.println("Step Event!"); 
      go = true; 
     } 
    } 
} 
相關問題