[Java性能剖析]JPDA 3)JDI/Debuger

     参考:http://java.sun.com/javase/6/docs/jdk/api/jpda/jdi/index.html
     JDI(Java Debug Interface)为Java调试器的开发提供了标准的接口,我们可以通过此构建标准的Java调试器。如JPDA架构图所示,通过Front-end、Transport(交互机制)和Back-end的交互,JDI对外使用Java语言提供了一个JVM TI的功能子集的高级接口(并非所有JVM TI功能都可以通过JDI访问到)。需要注意的是,JDI实现上不会太多考虑性能上的问题,因此一般不会使用JDI来构建性能剖析相关工具。
     1.主要的API

  • com.sun.jdi.connect.AttachingConnector:连接器,通过该连接器可以连接到一个运行中的JVM上
  • com.sun.jdi.VirtualMachine:远程/本地运行JVM的映像,类似于JVM TI中的jvmEnv对象
  • com.sun.jdi.request.EventRequestManager:事件请求管理器,通过该管理器进行事件注册
  • com.sun.jdi.ThreadReference:线程引用,可以通过此类获得线程相关的信息,譬如线程状态、线程栈等

     2.范例
     我们通过一个范例来了解一下JDI的使用,本范例首先获取到当前所有线程的信息,然后注册方法进入和退出事件,同时打印进入和退出信息。(如下程序需要tools.jar包)
     1)在被调试的JVM上启动调试Back end:在被调试的JVM启动参数中增加如下参数

-agentlib:jdwp=transport=dt_socket,address=localhost:8000,server=y,suspend=n

    具体参数的配置可参见《Connection and Invocation Details
     2)连接到被调试的JVM上
     由于Back-end的transport使用的是dt_socket的方式,首先需要获得一个dt_socket的AttachConnector

VirtualMachineManager vmManager = Bootstrap.virtualMachineManager();
List connectors = vmManager.attachingConnectors();
AttachingConnector socketAttachingConnector = null;
for (int i = 0; i < connectors.size(); i++)
{
        Connector connector = (Connector) connectors.get(i);
        Transport transport = connector.transport();
        if (”dt_socket”.equals(transport.name()))
        {
            socketAttachingConnector = (AttachingConnector) connector;
            break;
        }
}

     连接到被调试的JVM上

Map arguments = socketAttachingConnector.defaultArguments();
Connector.Argument hostArg = (Connector.Argument) arguments.get(HOST);
Connector.Argument portArg = (Connector.Argument) arguments.get(PORT);

hostArg.setValue(“127.0.0.1”);
portArg.setValue(“8000”);

VirtualMachine jvm = socketAttachingConnector.attach(arguments);

     3)打印当前线程信息

List<ThreadReference> threadReferences = jvm.allThreads();
for (ThreadReference tr : threadReferences)
{
      System.out.print("Thread[" + tr.name() + "] : ");
      //线程状态
      switch (tr.status())
       {
            case ThreadReference.THREAD_STATUS_MONITOR:
                System.out.println(" Waiting");
                break;
            case ThreadReference.THREAD_STATUS_NOT_STARTED:
                System.out.println(" Not Start");
                break;
            case ThreadReference.THREAD_STATUS_RUNNING:
                System.out.println(" Running");
                break;
            case ThreadReference.THREAD_STATUS_SLEEPING:
                System.out.println(" Sleepping");
                break;
            case ThreadReference.THREAD_STATUS_UNKNOWN:
                System.out.println(" Unknow");
                break;
            case ThreadReference.THREAD_STATUS_WAIT:
                System.out.println(" Wait");
                break;
            case ThreadReference.THREAD_STATUS_ZOMBIE:
                System.out.println(" Finish");
                break;
      }
       boolean suspend = tr.isSuspended();
       //注意,只有suspend的线程才能获得其线程栈,因此需要将其线suspend一下
       if (!suspend)
       {
           tr.suspend();
       }
        List<StackFrame> frames = tr.frames();
        for (StackFrame frame : frames)
       {
            System.out.println("-----"
                        + frame.location().method().toString() + ":"
                        + frame.location().lineNumber());
        }
           
         System.out.println("count:" + tr.entryCount());

         if (!suspend)
        {
              tr.resume();
        }
         frames = null;
}

     4)注册方法进入和退出事件,在实现调试器的时候,我们可以通过注册一个BreakPoint事件,在事件发生时挂住执行线程,然后检查事件发生对象的信息来实现最常见的断点调试功能,或者Step事件来完成单步执行功能

EventRequestManager eventRequestManager = jvm.eventRequestManager();
MethodEntryRequest methodEntryRequest = eventRequestManager.createMethodEntryRequest();
methodEntryRequest.addClassExclusionFilter("java.*");//设置过滤器,对过滤器中的Class不捕获其实践
methodEntryRequest.addClassExclusionFilter("sun.*");
methodEntryRequest.addClassExclusionFilter("javax.*");
methodEntryRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);//这个属性一定要设,
默认事件发生时会suspend住执行线程
methodEntryRequest.enable();
       
MethodExitRequest methodExitRequest = eventRequestManager.createMethodExitRequest();
methodExitRequest.addClassExclusionFilter("java.*");
methodExitRequest.addClassExclusionFilter("sun.*");
methodExitRequest.addClassExclusionFilter("javax.*");
methodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
methodExitRequest.enable();

     5)处理事件

EventQueue eventQueue = jvm.eventQueue();
EventSet eventSet;
while (true)
{
    eventSet = eventQueue.remove();
    EventIterator eventIterator = eventSet.eventIterator();
    while (eventIterator.hasNext())
    {
            Event event = (Event) eventIterator.next();
            execute(event);
    }
}

        打印处理信息

private void execute(Event event) throws Exception
{
	if (event instanceof MethodEntryEvent)
	{
		System.out.println("Mehtod Entry:" + ((MethodEntryEvent) event).method());
	}
	else if (event instanceof MethodExitEvent)
	{
		System.out.println("Mehtod Exi:" + ((MethodExitEvent) event).method());
	} 
}
 

你可能感兴趣的:(java,jvm,thread,socket,sun)