scala本地调试_如何编写自己的Java / Scala调试器

scala本地调试

在本文中,我们将探讨Java / Scala调试器的编写和工作方式。 诸如Windows的WinDbg或Linux / Unix的gdb之类的本机调试器通过操作系统直接提供给它们的钩子来获取其功能,以监视和操纵外部进程的状态。 JVM充当OS之上的抽象层,它提供了自己的独立体系结构来调试字节码。 blog_MyDebugger2

该框架及其API是完全开放的,有文档的且可扩展的,这意味着您可以轻松编写自己的调试器。 该框架的当前设计由两个主要部分组成-JDWP协议和JVMTI API层。 每种方法都有其各自的优点和用例,它们可以最佳地发挥作用。

JDWP协议

Java调试器有线协议通常用于在网络上通过二进制消息在调试器和被调试进程之间传递请求和接收事件(例如线程状态或异常的更改)。 该体系结构背后的概念是在两者之间建立尽可能多的隔离。 这是为了减少让调试器在运行目标代码时更改其执行的海森堡效应(物理学家维尔纳,而不是友好的Meth Cooking Walt )。

从目标进程中删除尽可能多的调试器逻辑也可以帮助确保已调试VM状态的更改(例如,“停止世界” GC或OutOfMemoryErrors)不会影响调试器本身。 为了使事情变得更容易,JDK附带了JDI (Java调试器接口),它提供了协议的完整调试器端实现,并具有连接,分离,监视和操纵目标VM的状态的能力。

例如,该协议与Eclipse的调试器使用的协议相同。 如果查看在IDE调试时传递给Java进程的命令行参数,您会注意到Eclipse传递给它的其他参数(-agentlib:jdwp = transport = dt_socket,…)来启用JVM调试,并且还会建立发送请求和事件的端口。

JVMTI API

现代JVM调试器体系结构中的第二个关键组件是一组本机API,涵盖了与JVM操作相关的广泛领域,称为JVM工具接口 (即JVMTI)。 与JDWP不同,JVMTI被设计为一组C / C ++ API,并且具有JVM动态加载使用API​​提供的命令的预编译库(例如.dll或.so)的机制。

这种方法与JDWP的不同之处在于,它实际上在目标进程内部执行调试器。 这增加了调试器在性能和稳定性方面影响应用程序代码的可能性。 但是,关键优势在于能够以近乎实时的方式直接与JVM交互。

由于JVMTI提供了一组功能强大的低级API集,所以我认为有必要进一步深入研究并解释其工作原理,以及可以使用哪些出色的功能。 可通过JDK随附的jvmti.h获得API标头。

编写调试器库

编写自己的调试器需要使用C ++创建本机OS库。 在这种情况下,您的“主要”功能看起来像–

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void*)

当调试器代理由JVM加载时,该函数将由JVM调用。 传递给您的日益重要的JavaVM指针将为您提供与JVM对话所需的一切。 它引入了JavaVM :: GetEnv方法中可用的jvmtiEnv类,使您能够通过功能和事件的概念与JVMTI层进行交互。

JVMTI功能

编写调试器的关键方面之一是要特别注意调试器代码对目标进程的影响。 这对于本机调试器库尤其重要,在该库中,您的代码与应用程序非常紧密地运行。 为了帮助您更好地控制调试器如何影响代码的执行,JVMTI规范引入了功能的概念。

在编写调试器时,您可以提前告诉JVM您打算使用哪些API命令或事件集(即设置断点,挂起线程等)。 这使JVM可以提前为此做准备,并且使您可以更好地控制调试器的运行时开销。 这种方法还使来自不同供应商的JVM能够以编程方式告诉您整个JVMTI规范中当前支持哪些API命令。

并非所有能力都是平等的 。 某些功能的性能开销相对较小。 其他有趣的事件,例如can_generate_exception_events用于在代码中引发异常时接收回调,或can_generate_monitor_events用于在获取锁时接收回调,则成本更高。 原因是它们阻止JVM在JIT编译过程中完全优化代码,并可能迫使JVM在运行时进入解释模式。

其他功能,例如can_generate_field_modification_events用于在设置目标对象字段(即设置监视)时接收通知,其成本甚至更高,从而使代码执行速度大大降低。 即使JVM支持同时加载多个本机库,HotSpot中的某些功能(例如can_suspend用于挂起和恢复线程)也只能一次声明一个库。

在构建Takipi的生产调试器时,我们面临的最困难的部分之一就是提供类似的功能而又不会产生这种开销(在以后的文章中会介绍更多)。

设置回调 。 收到一系列功能后,下一步就是设置回调,JVM将调用这些回调以让您知道实际发生的时间。 这些回调中的每一个都会提供有关已发生事件的相当深入的信息。 例如,对于异常回调,此信息将包括引发异常的字节码位置,线程,异常对象以及是否以及将在何处捕获该异常。

void JNICALL ExceptionCallback(jvmtiEnv *jvmti,JNIEnv *jni, jthread thread, jmethodID method,jlocation location, jobject exception,jmethodID catch_method, jlocation catch_location)

重要的是要注意,功能的开销有时分为两部分。 第一部分仅是通过启用它来完成的,因为这将导致JIT编译器以不同的方式编译事物,从而产生对代码进行调用的潜力。 第二部分是在您实际安装回调函数时出现的,因为它会导致JVM在运行时选择优化程度较低的执行路径,通过这些路径,它可以调用您的代码,并带来解析和传递的额外开销。您有意义的数据。

断点和手表 。 您的调试器可以提供在运行时检查特定状态的熟悉功能,例如SetBreakpoint以通知JVM在特定字节代码指令处挂起执行,或者SetFieldModificationWatch在字段被修改时暂停执行。 到那时,您可以使用其他补充功能,例如GetStackTraceGetThreadInfo来了解有关您在代码中当前位置的更多信息并将其报告。

如下所示的大多数JVMTI函数都使用称为jmethodID和jclass的抽象句柄来引用类和方法(如果您曾经编写过Java Native Interface代码,则应该很熟悉)。 提供了诸如GetMethodNameGetClassSignature之类的附加功能,以帮助您从类的常量池中获取实际的符号名称。 然后,您可以使用它们以可读格式记录数据或将其呈现在UI中,就像我们每天在IDE中看到的那样。

附加调试器

编写调试器库后,下一步就是将其附加到JVM。 有几种方法可以做到–

1.连接JDWP 。 如果要编写基于JDWP的调试器,则需要以– agentlib:jdwp = transport = dt_socket,suspend = y,address = localhost:<port>的形式向调试对象添加启动参数以通过线路启用调试。 这些参数详细说明了调试器和目标(在本例中为套接字)之间的通信形式,以及是否以挂起模式启动调试对象。

2.附加JVMTI库 。 JVM通过传递给debuggee进程并指向您的库在磁盘上的位置的agentpath命令行参数加载JVMTI库。

另一种方法是将代理程序命令行参数附加到全局JAVA_TOOL_OPTIONS环境变量,该环境变量将由每个新JVM拾取,并且其值会自动附加到其现有参数列表中。

3.远程连接 。 附加调试器的另一种方法是使用远程附加API 。 这个简单而强大的API使您可以将代理附加到正在运行的JVM进程,而无需使用任何命令行参数启动它们。 不利的一面是您将无法使用通常需要的某些功能,例如can_generate_exception_events ,因为这些功能仅在VM启动时才需要-不幸的是,调试器有些麻烦了。

您可以下载Takipi的生产调试器,以在此处查看其中的一些方法。

参考: Takipi博客上的JCG合作伙伴 Tal Weiss提供了如何编写自己的Java / Scala调试器的信息 。

翻译自: https://www.javacodegeeks.com/2013/09/how-to-write-your-own-java-scala-debugger.html

scala本地调试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346089.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java content()_Java contentEquals() 方法

全屏Java contentEquals() 方法contentEquals() 方法用于将将此字符串与指定的 StringBuffer 比较。语法public boolean contentEquals(StringBuffer sb)参数sb -- 要与字符串比较的 StringBuffer。返回值如字符串与指定 StringBuffer 表示相同的字符序列&#xff0c;则返回 tr…

通过这5个简单的技巧减少GC开销

编写代码的五种简单方法&#xff0c;可提高内存效率&#xff0c;而无需花费更多时间或降低代码可读性 垃圾回收会为您的应用程序增加多少开销&#xff1f; 您可能不知道确切的数字&#xff0c;但您确实知道总有改进的余地。 尽管自动GC是最有效的过程&#xff0c;但是如果它过…

内部简单二进制编码(SBE)

SBE是用于金融行业的非常快速的序列化库&#xff0c;在本博客中&#xff0c;我将介绍一些使其快速发展的设计选择。 序列化的全部目的是对消息进行编码和解码&#xff0c;并且有很多可用的选项&#xff0c;从XML&#xff0c;JSON&#xff0c;Protobufer&#xff0c;Thrift&…

mingw64 下 java_在 Windows 10 64 位下安装 Mingw-w64

1、MinGW 的全称是&#xff1a;Minimalist GNU on Windows 。打开网址&#xff1a;http://www.mingw-w64.org/doku.php/download &#xff0c;选择 MingW-W64-builds。如图1图12、下载包名&#xff1a;mingw-w64-install.exe。安装时报错&#xff1a;Cannot download repositor…

java实现layui分页_layui如何实现数据分页功能

我们先来看下官网的演示画面。具体代码&#xff1a;页面引入layui.css、 layui.js前台jsvar limitcount 10;var curnum 1;//列表查询方法function productsearch(productGroupId,start,limitsize) {layui.use([table,laypage,laydate], function(){var table layui.table,la…

java 合并到一行_mysql中将多行数据合并成一行数据

一个字段可能对应多条数据&#xff0c;用mysql实现将多行数据合并成一行数据例如&#xff1a;一个活动id(activeId)对应多个模块名(modelName),按照一般的sql语句&#xff1a;1 SELECT am.activeId,m.modelName2 FROM activemodel am3 JOIN model m4 ON am.modelId m.modelId5…

容器化Spring Data Cassandra应用程序

我正在继续学习Docker的旅程。 在这一点上&#xff0c;我仍然保持简单。 这次&#xff0c;我将解决将Spring和Cassandra应用程序转换为使用容器而不是在主机上本地运行的问题。 更准确地说&#xff0c;使用Spring Data Cassandra整理应用程序。 我希望我前几天看过进行此更改。…

使用React和Spring Boot构建一个简单的CRUD应用

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 React的设计使创建交互式UI变得轻松自如。 它的状态管理非常有效&#xff0c;并且仅在…

使用CUBA进行开发–是Spring的重大转变吗?

阅读另一个供内部公司使用的Web项目的要求时&#xff0c;您&#xff08;至少是我自己&#xff09;通常会看到一个很普通的集合&#xff1a;定义明确的数据存储结构&#xff08;或有时是现有的旧式DB&#xff09;&#xff0c;大量的数据输入形式&#xff0c;非常复杂的业务逻辑&…

java 伴随矩阵_C#计算矩阵的逆矩阵方法实例分析

本文实例讲述了C#计算矩阵的逆矩阵方法。分享给大家供大家参考。具体如下&#xff1a;1.代码思路1)对矩阵进行合法性检查&#xff1a;矩阵必须为方阵2)计算矩阵行列式的值(Determinant函数)3)只有满秩矩阵才有逆矩阵&#xff0c;因此如果行列式的值为0(在代码中以绝对值小于1E-…

java 代码造假_老板居然让我在Java项目中“造假”

1. 前言老板说&#xff0c;明天甲方要来看产品&#xff0c;你得造点数据&#xff0c;而且数据必须是“真”的&#xff0c;演示效果要好看一些&#xff0c;这样他才会买我们的产品&#xff0c;我好明年给你换个嫂子。一般开发接到这种过分要求都不会很乐意去做&#xff0c;这完全…

nginx php环境搭建_php+nginx环境配置

本篇文章的内容是PHP和nginx环境的配置&#xff0c;在这里分享给大家&#xff0c;也给有需要的朋友一个参考phpnginx环境配置1、首先需要准备的应用程序包。nginx&#xff1a;nginx/Windows-1.0.4php&#xff1a;php-5.2.16-nts-Win32-VC6-x86.zip (nginx下php是以FastCGI的方式…

javaone_旅行报告:JavaOne 2013 –重归荣耀

javaone我已经回来几天了&#xff0c;需要赶上过去几天一直搁置的所有事情。 对我来说&#xff0c;这是一年中最忙的时间。 JavaOne和OpenWorld在旧金山的整整一周。 一个非常简短的旅行报告。 年度ACED简报 你们中许多人都知道我是Oracle社区认可计划&#xff08;称为“ ACE计…

php如何禁用浏览器的缓存,php如何禁止浏览器使用缓存页面

【摘要】PHP即“超文本预处理器”&#xff0c;是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言&#xff0c;与C语言类似&#xff0c;是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。下面是php如何禁止浏览器使用缓存页面&#xff0c;让我…

使用Java EE和OIDC构建Java REST API

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 Java EE允许您使用JAX-RS和JPA快速轻松地构建Java REST API。 Java EE是保护伞标准规…

通过JavaFX标注制作动画效果

在本文中&#xff0c;您将学习如何使用JavaFX的动画API创建标注。 您可以在https://www.youtube.com/watch?vXTHbB0LRdT4的 YouTube网站上查看这些标注的演示示例。 什么是标注&#xff1f; 我敢肯定&#xff0c;您已经看过广告或科幻电影&#xff0c;它们使用在图像顶部显示…

使用trackBy启动流程

仍然沿用Corda Services的趋势&#xff0c;我还有其他一些技巧可帮助您的CorDapp顺利工作。 这次&#xff0c;我们将重点关注使用trackBy从服务内部启动流以及如果您不小心可能会引起的离散问题。 这应该是一个相对简短的职位&#xff0c;因为我可以依靠之前的职位&#xff1a…

java+springmvc+vo,springmvc+mybatis的实例详解

前面讲到&#xff1a;SpringSpringMVCMyBatis深入学习及搭建(十三)——SpringMVC入门程序(二)1.需求使用springmvc和mybatis完成商品列表查询。2.整合思路springmvcmybatis的系统架构&#xff1a;第一步&#xff1a;整合dao层mybatis和spring整合&#xff0c;通过spring管理map…

了解为什么这个直观的工具是您团队的通用团队管理工具

每个项目管理工具都试图做同样的工具性工作&#xff1a;保持团队联系&#xff0c;按任务执行和按时完成重大计划。 但是市场变得非常拥挤&#xff0c;并且有充分的理由-没有平台似乎对人们需要看的东西以及应该如何显示这些信息具有正确的感觉&#xff0c;以便它们既可行又相关…

模型服务:流处理与使用Java,gRPC,Apache Kafka,TensorFlow的RPC / REST

机器学习/深度学习模型可以通过不同的方式进行预测。 我的首选方法是将分析模型直接部署到流处理应用程序&#xff08;如Kafka Streams或KSQL &#xff09;中。 您可以例如使用TensorFlow for Java API 。 这样可以实现最佳延迟和外部服务的独立性。 在我的Github项目中可以找到…