JPDA 架构研究20 - JDI的事件请求和处理模块

简介:

引入:

上文主要讲解了JDI的连接模块来建立Debugger到Target VM之间的连接,这里主要讲解事件请求和处理模块。它们都在com.sun.jdi.event和com.sun.jdi.request包中。


分析:


Part 1:查看JDI中定义的事件类型

JDI中事件的接口叫Event . 

1
2
3
4
public  abstract  interface  Event  extends  Mirror
{
   public  abstract  EventRequest request();
}

它定义了18种具体的事件类型,如下:

ClassPrepareEvent 装载某个指定的类所引发的事件
ClassUnloadEvent 卸载某个指定的类所引发的事件
BreakingpointEvent 设置断点所引发的事件
ExceptionEvent 目标虚拟机运行中抛出指定异常所引发的事件
MethodEntryEvent 进入某个指定方法体时引发的事件
MethodExitEvent 某个指定方法执行完成后引发的事件
MonitorContendedEnteredEvent 线程已经进入某个指定 Monitor 资源所引发的事件
MonitorContendedEnterEvent 线程将要进入某个指定 Monitor 资源所引发的事件
MonitorWaitedEvent 线程完成对某个指定 Monitor 资源等待所引发的事件
MonitorWaitEvent 线程开始等待对某个指定 Monitor 资源所引发的事件
StepEvent 目标应用程序执行下一条指令或者代码行所引发的事件
AccessWatchpointEvent 查看类的某个指定 Field 所引发的事件
ModificationWatchpointEvent 修改类的某个指定 Field 值所引发的事件
ThreadDeathEvent 某个指定线程运行完成所引发的事件
ThreadStartEvent 某个指定线程开始运行所引发的事件
VMDeathEvent 目标虚拟机停止运行所以的事件
VMDisconnectEvent 目标虚拟机与调试器断开链接所引发的事件
VMStartEvent 目标虚拟机初始化时所引发的事件


Part 2:事件集的概念

事件集是事件发送的最小单位,并且事件集一旦被创建,则不可以被修改。

1
2
3
4
5
6
7
8
public  abstract  interface  EventSet  extends  Mirror, Set<Event>
{
   public  abstract  int  suspendPolicy();
 
   public  abstract  EventIterator eventIterator();
 
   public  abstract  void  resume();
}

它也提供了迭代器来访问事件集内的事件。


Part 3:事件队列

事件队列(EventQueue)的拥有者是目标虚拟机,EventQueue 将这些事件集以“先进先出”策略依次地发送到调试器端。EventQueue 负责管理来自目标虚拟机的事件,一个被调试的目标虚拟机上有且仅有一个 EventQueue实例。特别地,随着一次事件集的发送,目标虚拟机上可能会有一部分的线程因此而被挂起。如果一直不恢复这些线程,有可能会导致目标虚拟机挂机。


Part 4: JDI事件请求

正如Part1 所说,Event接口定义了request方法,该方法会返回由调试器Debugger发出的针对该事件的事件请求(EventRequest)。事件请求是由调试器向目标虚拟机发出的,目的是请求目标虚拟机在发生指定的事件后通知调试器。只有当调试器发出的请求与目标虚拟机上发生的事件匹配时,这些事件才会被分发到各个事件集,进而等待发送至调试器端。

(注意:这里可能有点绕口,一句话概括就是 EventRequest总是由Debugger发向Target VM ,而当请求与目标虚拟机上发生事件匹配,则事件会被归到EventSet中,EventSet会被Target VM的EventQueue所管理,并且按照FIFO原则发送到Debugger)


当然了,Debugger发送给Target VM的所有事件请求,不一定Target VM 都感兴趣。因此JDI提供了事件的过滤机制,来删选出最终真正要发送给Target VM的事件。

EventRequest中提供了一组addXXXFilter()方法来给某个事件请求添加一个或者多个过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  public  void  addCountFilter( int  count)
     throws  InvalidRequestStateException
   {
     checkDisabled();
     if  ( this .fCountFilters ==  null ) {
       this .fCountFilters =  new  ArrayList();
     }
     this .fCountFilters.add( new  Integer(count));
   }
 
   public  void  addThreadFilter(ThreadReference threadFilter)
     throws  ObjectCollectedException, VMMismatchException, InvalidRequestStateException
   {
     checkVM(threadFilter);
     checkDisabled();
     if  (threadFilter.isCollected())
       throw  new  ObjectCollectedException();
     if  ( this .fThreadFilters ==  null ) {
       this .fThreadFilters =  new  ArrayList();
     }
     this .fThreadFilters.add(threadFilter);
   }
 
   public  void  addClassFilter(ReferenceType filter)
     throws  VMMismatchException, InvalidRequestStateException
   {
     checkVM(filter);
     checkDisabled();
     if  ( this .fClassFilterRefs ==  null ) {
       this .fClassFilterRefs =  new  ArrayList();
     }
     this .fClassFilterRefs.add(filter);
   }
 
   public  void  addClassFilter(String filter)
     throws  InvalidRequestStateException
   {
     checkDisabled();
     if  ( this .fClassFilters ==  null ) {
       this .fClassFilters =  new  ArrayList();
     }
     this .fClassFilters.add(filter);
   }
 
   public  void  addClassExclusionFilter(String filter)
     throws  InvalidRequestStateException
   {
     checkDisabled();
     if  ( this .fClassExclusionFilters ==  null ) {
       this .fClassExclusionFilters =  new  ArrayList();
     }
     this .fClassExclusionFilters.add(filter);
   }
 
   public  void  addLocationFilter(LocationImpl location)
     throws  VMMismatchException
   {
     checkDisabled();
 
     checkVM(location);
     if  ( this .fLocationFilters ==  null ) {
       this .fLocationFilters =  new  ArrayList();
     }
     this .fLocationFilters.add(location);
   }
 
   public  void  addExceptionFilter(ReferenceTypeImpl refType,  boolean  notifyCaught,  boolean  notifyUncaught)
     throws  VMMismatchException
   {
     checkDisabled();
 
     if  (refType !=  null ) {
       checkVM(refType);
     }
     if  ( this .fExceptionFilters ==  null ) {
       this .fExceptionFilters =  new  ArrayList();
     }
     ExceptionFilter filter =  new  ExceptionFilter();
     filter.fException = refType;
     filter.fNotifyCaught = notifyCaught;
     filter.fNotifyUncaught = notifyUncaught;
     this .fExceptionFilters.add(filter);
   }
 
   public  void  addFieldFilter(FieldImpl field)
     throws  VMMismatchException
   {
     checkDisabled();
 
     checkVM(field);
     if  ( this .fFieldFilters ==  null ) {
       this .fFieldFilters =  new  ArrayList();
     }
     this .fFieldFilters.add(field);
   }
 
   public  void  addStepFilter(ThreadReferenceImpl thread,  int  size,  int  depth)
     throws  VMMismatchException
   {
     checkDisabled();
 
     checkVM(thread);
 
     if  ( this .fThreadStepFilters ==  null ) {
       this .fThreadStepFilters =  new  ArrayList();
     }
     ThreadStepFilter filter =  new  ThreadStepFilter();
     filter.fThread = thread;
     filter.fThreadStepSize = size;
     filter.fThreadStepDepth = depth;
     this .fThreadStepFilters.add(filter);
   }
 
   public  void  addInstanceFilter(ObjectReference instance)
   {
     checkDisabled();
     checkVM(instance);
     if  ( this .fInstanceFilters ==  null ) {
       this .fInstanceFilters =  new  ArrayList();
     }
     this .fInstanceFilters.add(instance);
   }
 
   public  void  addSourceNameFilter(String pattern)
   {
     checkDisabled();
     if  ( this .fSourceNameFilters ==  null ) {
       this .fSourceNameFilters =  new  ArrayList();
     }
     this .fSourceNameFilters.add(pattern);
   }


Part 5: Target VM对于事件请求(EventRequest)的管理

在JDI中,事件请求的管理是通过EventRequestManager来完成的。它有许多createXXXRequest方法来创建不同类型的事件请求,也有许多deleteXXXRequest方法来删除不同类型的事件请求,还有xxxRequests方法来列出各种类型的事件请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package  com.sun.jdi.request;
 
import  com.sun.jdi.Field;
import  com.sun.jdi.Location;
import  com.sun.jdi.Mirror;
import  com.sun.jdi.ReferenceType;
import  com.sun.jdi.ThreadReference;
import  java.util.List;
 
public  abstract  interface  EventRequestManager  extends  Mirror
{
   public  abstract  ClassPrepareRequest createClassPrepareRequest();
 
   public  abstract  ClassUnloadRequest createClassUnloadRequest();
 
   public  abstract  ThreadStartRequest createThreadStartRequest();
 
   public  abstract  ThreadDeathRequest createThreadDeathRequest();
 
   public  abstract  ExceptionRequest createExceptionRequest(ReferenceType paramReferenceType,  boolean  paramBoolean1,  boolean  paramBoolean2);
 
   public  abstract  MethodEntryRequest createMethodEntryRequest();
 
   public  abstract  MethodExitRequest createMethodExitRequest();
 
   public  abstract  MonitorContendedEnterRequest createMonitorContendedEnterRequest();
 
   public  abstract  MonitorContendedEnteredRequest createMonitorContendedEnteredRequest();
 
   public  abstract  MonitorWaitRequest createMonitorWaitRequest();
 
   public  abstract  MonitorWaitedRequest createMonitorWaitedRequest();
 
   public  abstract  StepRequest createStepRequest(ThreadReference paramThreadReference,  int  paramInt1,  int  paramInt2);
 
   public  abstract  BreakpointRequest createBreakpointRequest(Location paramLocation);
 
   public  abstract  AccessWatchpointRequest createAccessWatchpointRequest(Field paramField);
 
   public  abstract  ModificationWatchpointRequest createModificationWatchpointRequest(Field paramField);
 
   public  abstract  VMDeathRequest createVMDeathRequest();
 
   public  abstract  void  deleteEventRequest(EventRequest paramEventRequest);
 
   public  abstract  void  deleteEventRequests(List<?  extends  EventRequest> paramList);
 
   public  abstract  void  deleteAllBreakpoints();
 
   public  abstract  List<StepRequest> stepRequests();
 
   public  abstract  List<ClassPrepareRequest> classPrepareRequests();
 
   public  abstract  List<ClassUnloadRequest> classUnloadRequests();
 
   public  abstract  List<ThreadStartRequest> threadStartRequests();
 
   public  abstract  List<ThreadDeathRequest> threadDeathRequests();
 
   public  abstract  List<ExceptionRequest> exceptionRequests();
 
   public  abstract  List<BreakpointRequest> breakpointRequests();
 
   public  abstract  List<AccessWatchpointRequest> accessWatchpointRequests();
 
   public  abstract  List<ModificationWatchpointRequest> modificationWatchpointRequests();
 
   public  abstract  List<MethodEntryRequest> methodEntryRequests();
 
   public  abstract  List<MethodExitRequest> methodExitRequests();
 
   public  abstract  List<MonitorContendedEnterRequest> monitorContendedEnterRequests();
 
   public  abstract  List<MonitorContendedEnteredRequest> monitorContendedEnteredRequests();
 
   public  abstract  List<MonitorWaitRequest> monitorWaitRequests();
 
   public  abstract  List<MonitorWaitedRequest> monitorWaitedRequests();
 
   public  abstract  List<VMDeathRequest> vmDeathRequests();
}

有一点需要注意的是,这里由EventRequestManager创建的createXXXRequest的事件都是非激活的,因此这些事件请求当发送给Target VM不会起任何作用,除非调用EventRequest的setEnable(true)使得该事件进入激活状态。


Part 6: JDI中Debugger与Target VM之间的事件交互。

Step 1:Debugger调用Target VM的 eventQueue() 和 eventRequestManager() 分别获取唯一的 EventQueue 实例和 EventRequestManager 实例.


Step 2: Debugger通过 EventRequestManager 的 createXXXRequest() 创建需要的事件请求,并添加过滤器和设置挂起策略.

Step 3: Debugger通过EventQueue 获取来自Target VM的事件实例.

这个事件实例包含了许多信息,比如ThreadReference ,StackFrame,LocalVariable, Location,Method等,这些事件信息就包含了当前Target VM的一些现有状态信息和数据,Debugger就用这些数据交给Eclipse的相应的Debugger UI插件来显示结果。


总结:

在此文章中,我们涉及到了多个概念,这里把其中的类模型概括下:

wKiom1SGzHigR1adAAFDI0xXU0I825.jpg





本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1588043,如需转载请自行联系原作者
目录
相关文章
|
2月前
|
机器学习/深度学习 安全 算法
十大主流联邦学习框架:技术特性、架构分析与对比研究
联邦学习(FL)是保障数据隐私的分布式模型训练关键技术。业界开发了多种开源和商业框架,如TensorFlow Federated、PySyft、NVFlare、FATE、Flower等,支持模型训练、数据安全、通信协议等功能。这些框架在灵活性、易用性、安全性和扩展性方面各有特色,适用于不同应用场景。选择合适的框架需综合考虑开源与商业、数据分区支持、安全性、易用性和技术生态集成等因素。联邦学习已在医疗、金融等领域广泛应用,选择适配具体需求的框架对实现最优模型性能至关重要。
509 79
十大主流联邦学习框架:技术特性、架构分析与对比研究
|
26天前
|
安全 NoSQL MongoDB
XJ-Survey:这个让滴滴日均处理1.2亿次问卷请求的开源系统,今天终于公开了它的架构密码!
嗨,大家好,我是小华同学。今天为大家介绍一款由滴滴开源的高效调研系统——XJ-Survey。它功能强大,支持多类型数据采集、智能逻辑编排、精细权限管理和数据在线分析,适用于问卷、考试、测评等场景。采用 Vue3、NestJS 等先进技术栈,确保高性能与安全性。无论是企业还是个人,XJ-Survey 都是你不可错过的神器!项目地址:[https://github.com/didi/xiaoju-survey](https://github.com/didi/xiaoju-survey)
75 15
|
3月前
|
存储 JavaScript 开发工具
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
本次的.HarmonyOS Next ,ArkTS语言,HarmonyOS的元服务和DevEco Studio 开发工具,为开发者提供了构建现代化、轻量化、高性能应用的便捷方式。这些技术和工具将帮助开发者更好地适应未来的智能设备和服务提供方式。
93 8
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
|
3月前
|
机器学习/深度学习 算法 数据可视化
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
本文探讨了在量化交易中结合时序特征和静态特征的混合建模方法。通过整合堆叠稀疏降噪自编码器(SSDA)和基于LSTM的自编码器(LSTM-AE),构建了一个能够全面捕捉市场动态特性的交易系统。SSDA通过降噪技术提取股票数据的鲁棒表示,LSTM-AE则专注于捕捉市场的时序依赖关系。系统采用A2C算法进行强化学习,通过多维度的奖励计算机制,实现了在可接受的风险水平下最大化收益的目标。实验结果显示,该系统在不同波动特征的股票上表现出差异化的适应能力,特别是在存在明确市场趋势的情况下,决策准确性较高。
97 5
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
|
5月前
|
设计模式 前端开发 JavaScript
深入探索研究MVVM架构设计
【10月更文挑战第7天】
85 0
|
6月前
|
XML Java 数据库
在微服务架构中,请求常跨越多个服务,涉及多组件交互,问题定位因此变得复杂
【9月更文挑战第8天】在微服务架构中,请求常跨越多个服务,涉及多组件交互,问题定位因此变得复杂。日志作为系统行为的第一手资料,传统记录方式因缺乏全局视角而难以满足跨服务追踪需求。本文通过一个电商系统的案例,介绍如何在Spring Boot应用中手动实现日志链路追踪,提升调试效率。我们生成并传递唯一追踪ID,确保日志记录包含该ID,即使日志分散也能串联。示例代码展示了使用过滤器设置追踪ID,并在日志记录及配置中自动包含该ID。这种方法不仅简化了问题定位,还具有良好的扩展性,适用于各种基于Spring Boot的微服务架构。
80 3
|
6月前
|
编解码 Linux 开发工具
Linux平台x86_64|aarch64架构RTMP推送|轻量级RTSP服务模块集成说明
支持x64_64架构、aarch64架构(需要glibc-2.21及以上版本的Linux系统, 需要libX11.so.6, 需要GLib–2.0, 需安装 libstdc++.so.6.0.21、GLIBCXX_3.4.21、 CXXABI_1.3.9)。
163 0
|
7月前
|
消息中间件 缓存 Kafka
介绍基于事件的架构
介绍基于事件的架构
61 4
|
7月前
|
C# 微服务 Windows
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
161 0
|
7月前
|
Serverless 数据安全/隐私保护 开发者
Serverless 架构问题之阿里云函数计算在事件生态层面如何解决
Serverless 架构问题之阿里云函数计算在事件生态层面如何解决
68 0

热门文章

最新文章