参考: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());
}
}
分享到:
相关推荐
JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP),以及 Java 调试接口(JDI),本系列将会详细介绍这三个模块的内部细节、通过实例为读者揭开 JPDA 的面纱。本文是该系列的第一篇...
JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP),以及 Java 调试接口(JDI),本系列将会详细介绍这三个模块的内部细节、通过实例为读者揭开 JPDA 的面纱。
使用JPDA进行Java程序远程调试使用JPDA进行Java程序远程调试使用JPDA进行Java程序远程调试使用JPDA进行Java程序远程调试
基于JPDA的Java软件性能测试.pdf
使用matlab开发的M/N逻辑方法,实现航迹起始
文档内详细介绍了java的调试体系--JPDA,包括其接口,以及一些与虚拟机相关的知识
多目标跟踪JPDA算法实现,是学习JPDA算法的经典代码,建议下载下来看看。
JPDA主要由三个部分组成:Java虚拟机工具接口(JVMTI),Java调试线协议(JDWP),以及Java调试接口(JDI),本系列将会详细介绍这三个模块的内部细节、通过实例为读者揭开JPDA的面纱。本文是该系列的第一篇,将会...
采用JPDA数据关联算法实现两个个匀速运动目标的点迹与航迹的关联。上传的为压缩文件,解压后有两个m文件,一个是Data_JPDAF.m,另一个是JPDAF.m。将两个文件放到Matlab的同一个目录下,直接运行文件Data_JPDAF.m即可...
联合概率数据互联JPDA是数据关联算法之一,它的基本思想是:对应于观测数据落入跟踪门相交区域的情况,这些观测数据可能来源于多个目标。JPDA的目的在于计算观测数据与每一个目标之间的关联概率,且认为所有的有效...
matlab简单实现多目标跟踪的JPDA算法,供初学者参考
采用JPDA数据关联算法实现两个匀速运动目标的点迹与航迹的关联
能实现多目标跟踪中数据关联,对每个目标设置合适的跟踪门,在跟踪门内认为增加杂波产生数据
数据关联的JPDA算法 程序运行正常 注释详尽
Tool APIs java javac javadoc jar javap JPDA JConsole Java VisualVM Java DB Security Int'l RMI IDL Deploy Monitoring Troubleshoot Scripting JVM TI JRE RIAs Java Web Start Applet / Java Plug-in ...
多传感器/多目标跟踪的JPDA数据关联算法,在密集杂波环境下
Adaptation (JPDA) approach, to replace the frequently-used joint maximum mean discrepancy metric in transfer learning. During the distribution adaptation, JPDA improves the transferability between ...
数据关联的经典算法JPDA,包含杂波环境。