JVM调试和监控相关工具


内置JVM调试工具

HSDB

https://www.jianshu.com/p/e6eff89d3a58

JVM性能分析工具 Jprofiler GC 等监控

 https://www.cnblogs.com/cfas/p/16794648.html

jvm参数大全

https://www.cnblogs.com/cfas/p/16779902.html

 

 

阿里 Arthas(阿尔萨斯)的基本使用

https://arthas.aliyun.com/doc/contact-us.html

https://blog.csdn.net/weixin_37650458/article/details/123561000

 

 

JDWP 整理的介绍

https://www.cnblogs.com/cfas/p/16631908.html

 JDWP 协议官方文档

https://docs.oracle.com/en/java/javase/11/docs/specs/jdwp/jdwp-protocol.html

JDI 调试演示代码

https://blog.csdn.net/JimFire/article/details/120174611

JDI 的全面介绍

https://blog.51cto.com/supercharles888/1587958

 

内置jar包说明

  • rt.jar
    运行时包
  • dt.jar
    关于运行环境的类库
  • tools.jar
    工具类库,编译和运行需要的都是toos.jar里面的类分别是sun.tools.java. ; sun.tols.javac.;
  • ant-javafx.jar
    javaFX包的ant工具
  • charsets.jar
    Java 字符集,这个类库中包含 Java 所有支持字符集的字符
  • cldrdata.jar
    Unicode通用语言环境数据存储库
  • deploy.jar
    deploy.jar是Java部署堆栈的一部分,用于applet和Webstart应用程序。 deploy.jar是Java安装目录的常见部分 - 该文件运行某些产品的安装。
  • dnsns.jar
    与 DNS 有关
  • jaccess.jar
    Java Access Bridge是一种在Microsoft Windows DLL中公开Java Accessibility API的技术,使实现Java Accessibility API的Java应用程序和applet对Microsoft Windows系统上的辅助技术可见。 Java Accessibility API是Java Accessibility Utilities的一部分,它是一组实用程序类,可帮助辅助技术提供对实现Java Accessibility API的GUI工具包的访问。
  • javaws.jar
    是java提供的一种可以通过浏览器直接执行java应用程序的途径,它使你可以直接通过一个网页上的url连接打开一个java应用程序。
  • jce.jar
    Java 加密扩展类库,含有很多非对称加密算法在里面,但也是可扩展的。
  • jconsole.jar
    jconsole Jconsole控制台,Java监视和管理控制台
  • jfr.jar
    Flight Recorder Files 飞行记录器JFR(java flight recorder)
  • jfxrt.jar
    javaFx相关的java包
  • jfxswt.jar
    javaFx相关的与 swt有关java包
  • jsse.jar
    The Java Secure Socket Extension,Java安全套接字扩展
  • localedata.jar
    contains many of the resources needed for non US English locales,本地机器语言的数据,比如日期在使用中文时,显示的是“星期四”之类的
  • management-agent.jar
    JVM本身提供了一组管理的API,通过该API,我们可以获取得到JVM内部主要运行信息,包括内存各代的数据、JVM当前所有线程及其栈相关信息等等。各种JDK自带的剖析工具,包括jps、jstack、jinfo、jstat、jmap、jconsole等,都是基于此API开发的。
  • nashorn.jar
    A Next-Generation JavaScript Engine for the JVM,JVM的JavaScript解析引擎
  • packager.jar
    可以使用Java Packager工具从命令行编译、打包、签名和部署Java和JavaFX应用程序。它可以用来替代Ant任务或在IDE中构建应用程序。Java Packager工具不适用于Solaris平台。
  • plugin.jar
    按字面意思,应该是插件API的意思, 与UI和浏览器有关
  • resources.jar
    资源包(图片、properties文件)
    sa-jdi.jar
    ServiceAbility JDK SA工具 关于SA详情查看
  • sunec.jar
    JCE providers for Java Cryptography APIs,Java加密api的JCE提供程序
  • sunjce_provider.jar
    为JCE 提供的加密安全套件
  • sunpkcs11.jar
    PKCS#11 证书工具
  • zipfs.jar
    Zip File System Provider,Zip文件系统提供程序
 

ava 技术栈的程序员大多使用过远程调试。如果你还没有用过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 用于Java 5及以后,开启后JVM运行于JIT模式,速度更快。因为Java 5采用了HotSpot VM,增加了动态反优化技术,使得调试速度更快。通过这个选项长期开启调试支持也不会影响程序运行速度。同时还支持热交换技术,使得在调试的过程中可以修改Class的代码,从而更快速地定位到问题。

以上两种方式,都需要进一步配置远程调试参数,即“runjdwp:”和“jdwp=”后面的选项。选项具体配置如下。

第二步、在IntelliJ IDEA中,新建一个远程调试的运行配置(Run configuration):

第三步、点击调试按钮,就可以进行远程调试了。

注意要满足以下条件:

  1. 要确保本地代码与远程代码一致;
  2. 被调试的程序在编译的时候,加上了调试信息的(命令:javac -g ...)

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

有了远程调试经验的老手们可能会遇到一些实际问题。例如,有的bug在线上能够稳定复现,但是当我们对目标程序进行调试的时候,这个bug竟然神奇般地消失了。你有遇到过这样的问题吗?我就遇到过这样的问题。正是我遇到的这个诡异现象促使我全面了解了一遍java远程调试到底是怎么实现的,它对目标程序自身有什么影响?

比如,我们在debug一段程序的时候,需要设置断点,然后再单步执行。当程序运行到某个断点位置时,这个线程就会被suspend,等待我们的debugger告诉目标程序,下一步要怎么执行,是step还是resume还是run to cursor等。假如我们正在单步执行,又有新线程命中这个断点,那么这个线程是会继续执行还是会suspend呢?我们在debug的过程中,线程被暂停,GC又是怎么发生的,也被暂停了吗?线程被我们的断点暂停后,跟时间相关的代码会把我们调试导致的暂停的时间也包含在内吗?诸如此类的问题,要想弄明白,都需要我们深入了解java远程调试这个底层技术。

3. Java Platform Debugger Architecture (JPDA)

JPDA是Java实现调试功能的架构设计,主要目的是提供给工具开发商开发调试工具 (debugger application)。JPDA保证了调试工具可跨平台、跨JVM、跨JDK版本运行。

JPDA是分层设计的,总共分3层:

  1. Java VM Tool Interface (JVM TI): Java虚拟机工具接口层,位于JPDA最底层,负责定义由JVM提供的调试服务的接口,而JVM负责实现JVM TI接口。可见,Java程序的调试也是按照SPI(Service Provier Interface)设计模式设计的,把JVM的调试能力看作一种服务,通过接口来对外提供这种服务,而JVM负责调试功能的具体实现。
  2. Java Debug Wire Protocol (JDWP):负责被调试的进程和debugger前端之间的通信。JVM TI提供的调试服务是面向native语言的(C/C++),主要供JVM进程内部调用,因此需要通过JDWP来实现跨进程调试。
  3. Java Debug Interface (JDI):面向Java语言的最高层接口,供工具开发商快速开发debugger程序,实现远程调试。JDK推荐使用JDI开发debugger,从而获得java技术栈的跨平台运行能力。

JPDA架构图

  1. debuggee: 被调试进程,包含正在被调试的应用、运行应用的VM、debugger后端Java Virtual Machine: java的调试功能最终是由VM负责实现的。back-end: 主要职责是通信,把调试请求从debugger前端发送到VM,再把response返回回去。debugger后端与前端通信是基于JDWP协议。
  2. communication channel: debugger后端与debugger前端之间的连接,包含2个组件。connector: 通过connector建立连接。connector分三类:listening connector, attaching connector, launching connectortransport: 负责底层数据交换,可以用的transport有sockets, serial lines, 和 shared memory。
  3. front-end: 负责实现JDI接口

JPDA只是定义了接口规范 ,需要具体实现,才能实现java调试。

Oracle JDK 针对这3个接口,提供了参考实现,具体包含:

  1. 在VM上实现了JVM TI 接口
  2. 一个debugger back-end 实现(使用了JVM TI接口,实现了JDWP协议的debuggee一端)
  3. 一个debugger front-end 实现(使用了JDWP协议的debugger一端的功能,实现了JDI接口)
  4. 2个简单的基于JDI的调试工具,即jdb。

JDK提供的参考实现

JPDA是分层架构设计,其中的每一层都是可以替换的。调试工具可以基于JDI开发,也可以基于JDWP开发,或直接基于JVM TI开发。

Java中的调试功能的实现步骤

  1. VM提供调试服务,例如提供API用于设置断点,取消断点,设置watch point,单步执行、查看stack frame等。
  2. VM把调试功能封装成API,通过JVM TI接口的形式提供给调用方。
  3. debugger后端程序通过调用JVM TI获得调试信息或设置调试动作,然后按照JDWP协议进行封装,实现远程调试。
  4. debugger前端按照JDWP协议调用debugger后端功能,把功能封装成JDI接口。
  5. 调试工具,例如IntelliJ IDEA中的debugger,直接调用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的内部状态,可以实现各种各样的工具,例如 profiling(分析)、debugging(调试)、monitoring(监控)、thread analysis(线程分析) 和 coverage analysis等类型工具。

JVM的调试功能是在JVM内部实现,然后通过JVM TI接口开放给第三方工具厂商的。

JVM TI是一个双向接口。JVM TI的客户端(也就是agent)可以利用events功能感知到JVM中发生的事件,还可以通过functions功能来查询程序的状态和控制程序的执行。

这个agent与JVM在同一个进程中运行,它通过直接调用JVM TI接口与JVM通信。agent再被另外一个进程控制,这样实现java本地调试功能。

在windows系统上,agent一般是一个DLL库,在类unix系统上,agent一般是一个so文件。

agent是在JVM启动的时候,通过命令行选项加载的,有2种加载方式:

加载方式一

-agentlib:<agent-lib-name>=<options>brbragent-lib-name 指的是agent的名称broptions是传给这个agents的选项

加载方式二

-agentpath:<path-to-agent>=<options>

JVM TI 过于靠近底层,大部分工具是通过JPDA间接访问JVM TI的。

5. 远程调试通信协议:Java Debug Wire Protocol (JDWP)

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

JDWP实现debuggee和debugger之间的隔离,所以debugger可跨平台运行和调试。

隔离除了可以实现跨平台的优势以外,被调试的JVM中的GC、OOM等事件不会影响debugger自身运行。

JDWP只定义数据的格式,没有指定传输协议,只需一个简单API就可以支持多种传输方式。

JDWP简单,容易实现,灵活,便于扩展(JDWP设计考虑到了JDI的使用方便)。

JDWP Start Up(握手机制)

建立连接之后,首先要经过一次握手,然后才开始发送packet。

debugger → target vm: JDWP-Handshake

target vm → debugger: JDWP-Handshake

JDWP Packet (数据包)

packet分为2类:1. command packets 2. reply packets

debugger往target vm发送command packet,从而:1)获取信息 2)控制程序执行

target vm往debugger发送command packet,从而:通知debugger,vm中发生的事件(event)。

replay packet 用于通知操作是否成果和获取返回数据

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)
  • 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)
  • 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)
  • 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)
  • 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调试接口:Java Debug Interface (JDI)

JDI是JPDA架构中最高层Java API。通过调用JDI接口可以获得debugger需要的信息,也可以控制被调试程序的运行。

JDK通过SPI模式为JDI提供了具体实现(位于 lib/tools.jar),完整实现了JDWP协议后端部分,可以远程连接、Attach、监控和控制target JVM。

JDI组成部分

name desc
com.sun.jdi core package,定义了value, type 和 虚拟机的镜像
com.sun.jdi.connect 提供debugger和target vm之间的Connector实现,实现网络连接
com.sun.jdi.connect.spi 如果JDK自带的Connector实现不能满足需要,可以通过这里的接口自定义Connector
com.sun.jdi.event JDI中的event定义和处理工具
com.sun.jdi.request 用于实现满足特定条件就发送event

基于JDI开发debugger步骤

1. 调用JDI中用于建立与target vm建立连接的API,创建Connector。本地调试可以创建LaunchingConnector,远程调试可以创建AttachingConnector。

2. Connector创建好之后launch或者attach到target vm。

3. 设置event,例如ClassPrepareEvent、BreakpointRequest等:

例如设置断点可以创建BreakpointRequest

4. 断点触发之后,需要处理BreakpointEvent,例如打印所有变量

5. 综合起来

这个例子来自:

7. 基于JDI开发debugger的示例

JDK的一个子目录(JDK demo包)即 $JDK/demo/jpda 中,有3个JDI接口的使用示例(源码和文档)。

  1. trace:显示程序执行轨迹。
  2. jdb:JDK中自带的命令行调试工具。
  3. javadt:一个简单的GUI调试工具。

 

 
posted @ 2022-08-21 22:50  方东信  阅读(391)  评论(0编辑  收藏  举报