底层技术揭秘:java调试工具实现原理与使用技巧

      最后更新:2022-06-19 03:49:06 手机定位技术交流文章

      大多数Java技术堆中的程序员使用远程调试。如果你还没有使用Java远程调试,请仔细看这篇文章的第一节,即时提高调试效率几倍;对于使用Java远程调试的老年人,你有没有想过如何实现它的底部?今天的文章是揭示(程序员应该理解他们每天使用的工具,磨炼自己的技艺)

      1.基本Java远程调试操作

      默认的Java进程不支持远程调试,如果需要远程调试,在启动Java之前必须添加具体选项。

      首先,在启动JVM时,添加下列调试选项:

      1. Java 5以前:
        -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
      2. Java 5及以后:
        -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044

      两者之间有啥区别:

      "-Xdebug -Xrunjdwp"主要用于Java 5和以前。其中,"-Xdebug"是让JVM打开调试支持,打开调试函数需要jvm在解释执行模式中运行,因此,Java程序的执行速度变得非常缓慢;"-Xrunjdwp"是让JVM运行JDWP协议,从而允许远程调试。

      -agentlib:jdwp for Java 5 and later,开机后,JVM在JIT模式下运行,速度更快。因为Java5采用HotSpot VM,增强动态反优化技术,使得调试速度更快。通过此选项长期激活调试支持不会影响程序的运行速度。它还支持热交换技术,允许在调试过程中修改类代码,这样你就能更快地解决这个问题。

      上述两种方法需要进一步配置远程调试参数,即运行jdwp:和jdwp=之后的选项。

      第二步,在IntelliJ IDEA中,是创建远程调试运行配置:

      第三步是点击调试按钮并远程调试。

      注意,必须满足下列条件:

      1. 确保本地代码与远程代码相匹配;
      2. 在编译时将被调试的程序添加到调试信息中(command:javac -g..)

      2.IntelliJ IDEA或Eclipse如何实现调试功能

      有远程调试经验的老年人可能会遇到一些实际问题。例如,有些线上的错误是稳定的重复,但当我们调试目标程序时,虫子奇迹般地消失了.你曾经遇到过这样的问题吗?我有这样的问题。正是我遇到的这个奇怪的现象,使我重新完全理解如何实现Java远程调试,它对目标方案本身有什么影响?

      比如,当我们调试程序时,需要设置断点,然后再单步执行。当程序在交点上运行时,这个线程将被暂停,等待我们的调试程序告诉目标程序,下一步要怎么执行,它是步骤或恢复或运行到 kursor等.如果我们正在实施一个单一步骤,新的线程中还有另一个断头,那么这条线是否会继续下去,还是会停止?在调试过程中,线程被暂停,GC又发生了什么事?也被暂停了吗?当线被停在我们的断点之后,时间相关代码是否包括我们延迟的调试时间?诸如此类的问题,要想弄明白,我们需要深入了解Java远程调试的基本技术。

      3. Java Platform Debugger Architecture (JPDA)

      JPDA是为Java实现调试函数而设计的架构,主要为工具开发者提供调试应用程序。JPDA确保调试工具在平台、JVM和JDK版本中运行。

      JPDA分为三个层次:

      1. Java VM工具界面(JVM TI):Java VM工具界面,位于JPDA底部,负责定义JVM提供的调试服务的接口,JVM负责实现JVM TI接口.可见,Java程序调试也根据SPI(Service Provier Interface)设计模式设计,把JVM调试功能当作服务,通过一个接口向外部提供这些服务,JVM负责具体实现调试函数。
      2. Java Debug Wire Protocol(JDWP)负责调试过程与调试前端之间的通信。JVM TI提供的调试服务是母语(C/C++),主要用于内部调用JVM进程,因此,必须通过JDWP实现交叉过程调试。
      3. Java调试接口(JDI):Java语言的最高级别接口,工具开发者可以快速开发调试程序,实现远程调试。JDK建议使用JDI来开发调试器,因此,Java技术堆可以运行在多个平台上。

      JPDA架构图

      1. 调试程序:调试过程,调试后端Java虚拟机:Java的调试功能最终由VM实现。背景:主要责任是沟通,从调试器前端向VM发送调试请求,再次返回答复。调试器后端和前端通信基于JDWP协议。
      2. 通信通道:调试器后端与调试器前端之间的连接,包含2个组件。连接器: 通过连接器建立连接.连接器分为三个类别:连接器列表,连接器连接,启动连接器运输:负责基础数据交换,可用的传输包括插座、串行线和共享内存。
      3. 前端:负责实现JDI接口

      JPDA只定义接口规范,需要具体的实现实现Java调试。

      Oracle JDK提供了这些三个接口的参考实现,包括:

      1. 在VM上实现JVM TI接口
      2. 调试器后端实现(使用JVM TI接口实现JDWP协议的调试器端)
      3. 调试前端实现(使用JDWP协议调试端和实现JDI接口)
      4. 基于JDI的两个简单的调试工具,即jdb。

      JDK提供的参考实现

      JPDA是一个层级的架构设计,每个层可以被替换。 调试工具可以基于JDI开发,JDWP开发,或直接基于JVM TI开发。

      Java中调试函数的实现步骤

      1. 虚拟机提供调试服务,如设置故障点、取消故障点、设置监视点、单步执行、查看堆栈帧等。
      2. VM将调试函数包入API中,并通过JVM TI接口向调用者提供。
      3. 调试后端程序获取调试信息或通过调用JVM TI设置调试动作,然后根据JDWP协议将其封装并实现远程调试。
      4. 调试器前端根据JDWP协议调用调试器后端函数,并将函数封入JDI接口中。
      5. 调试工具,如IntelliJ IDEA的调试器,直接调用JDI实现调试功能。

      4.Java虚拟机工具接口(JVM TI)

      JVM TI(Java Virtual Machine Tool Interface)是本地编程接口(C++)。主要由工具开发者使用,例如, Eclipse和IntelliJ IDEA等工具。可以由JVM TI实现的功能包括:

      1. 查看Java应用程序的内部状态
      2. 控制Java应用程序的执行
      3. 查看JVM内部状态

      利用JVM TI访问JVM内部状态,各种工具可以实现,例子包括剖析、调试、监测、线程分析和覆盖分析。

      JVM的调试功能在JVM内部实现,并通过JVM TI接口向第三方工具制造商开放。

      JVM TI是一个双向接口,JVM TI客户端(即代理人)可以使用事件函数检测在JVM中发生的事件,也可以使用函数函数查询程序的状态和控制程序的执行。

      该代理在与JVM相同的进程中运行,通过直接调用JVM TI接口与JVM通信,然后由另一个进程控制代理,从而实现Java本地调试函数。

      在Windows系统中,代理通常是DLL库,在UNIX系统中,代理通常是这样文件。

      当JVM启动时,代理是通过命令行选项加载的。加载方法有两种:

      加载方式一

      加载方式二

      JVM TI太接近底部,大部分工具通过JPDA间接访问JVM TI。

      5.Java调试线协议(JDWP)

      JDWP是一个实现Java应用程序远程调试的通信协议,即jvm与调试器之间的通信,如线程状态的传输、异常信息等。

      JDWP实现了调试器和调试器之间的分离,因此调试器可以在多个平台运行和调试。

      除了隔离的跨平台优势之外,调试JVM中的GC和OOM事件不会影响调试器本身的操作。

      JDWP仅定义数据格式而不指定传输协议,一个简单的API可以支持多个传输模式。

      JDWP是简单、易于实现、灵活和可扩展的(JDWP设计考虑到使用JDI的便利)。

      JDWP启动

      连接建立后, 首先采取振动,然后发送一个数据包.

      debugger → target vm: JDWP-Handshake

      target vm → debugger: JDWP-Handshake

      JDWP包

      包分为两个类别: 1. 命令包 2. 答复包

      调试器向目标vm发送命令包,从而 1) 获取信息 2) 执行控制程序

      目标vm向调试器发送命令包,这样: 通知vm发生事件的调试器。

      重新播放包用于通知操作是否成功并取得返回数据

      Command Packet

      Reply Packet

      • Headerlength (4 bytes)id (4 bytes)flags (1 byte)command set (1 byte)command (1 byte)
      • data (Variable)
      • Headerlength (4 bytes)id (4 bytes)flags (1 byte)error code (2 bytes)
      • data (Variable)

      6.Java调试接口(JDI)

      JDI是JPDA架构中最高级别的Java API,通过调用JDI接口,调试程序可以获取所需的信息,并控制调试程序的运行。

      JDK通过SPI模式( lib/tools.jar)为JDI提供了具体的实现,它是一个完全实现的JDWP协议的后端,允许远程连接、连接、监控和控制目标JVM。

      JDI组成部分

      name

      desc

      com.sun.jdi

      核心包,定义值、类型和虚拟机器镜

      com.sun.jdi.connect

      提供调试器和目标vm之间的连接器实现,实现网络连接

      com.sun.jdi.connect.spi

      如果与JDK自驱动的连接器实现不符合要求,您可以在此定义连接器

      com.sun.jdi.event

      JDI事件定义和处理工具

      com.sun.jdi.request

      发送事件以满足特定条件

      基于JDI开发调试步骤

      1.JDI的调用用于创建一个API,它与目标vm建立连接并创建一个Connector。 本地调试可以创建 LaunchConnector,远程调试可以创建 AttachingConnector。

      2.创建连接器后,启动或连接到目标vm。

      3.设置一个事件,如ClassPrepareEvent, BreakpointRequest等:

      例如,设置一个断点可以创建一个断点请求


      4.在触发故障点后,必须处理故障点事件,例如打印所有变量

      7d992a643b071a3e67b510daa83d0fce.png

      本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/27711.html

          热门文章

          文章分类