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的时候,加上以下调试选项:
- Java 5以前:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044 - 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=”后面的选项。选项具体配置如下。
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123213-1974985086.jpg)
第二步、在IntelliJ IDEA中,新建一个远程调试的运行配置(Run configuration):
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123262-1993707944.jpg)
第三步、点击调试按钮,就可以进行远程调试了。
注意要满足以下条件:
- 要确保本地代码与远程代码一致;
- 被调试的程序在编译的时候,加上了调试信息的(命令: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层:
- Java VM Tool Interface (JVM TI): Java虚拟机工具接口层,位于JPDA最底层,负责定义由JVM提供的调试服务的接口,而JVM负责实现JVM TI接口。可见,Java程序的调试也是按照SPI(Service Provier Interface)设计模式设计的,把JVM的调试能力看作一种服务,通过接口来对外提供这种服务,而JVM负责调试功能的具体实现。
- Java Debug Wire Protocol (JDWP):负责被调试的进程和debugger前端之间的通信。JVM TI提供的调试服务是面向native语言的(C/C++),主要供JVM进程内部调用,因此需要通过JDWP来实现跨进程调试。
- Java Debug Interface (JDI):面向Java语言的最高层接口,供工具开发商快速开发debugger程序,实现远程调试。JDK推荐使用JDI开发debugger,从而获得java技术栈的跨平台运行能力。
JPDA架构图
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123211-460143176.jpg)
- debuggee: 被调试进程,包含正在被调试的应用、运行应用的VM、debugger后端Java Virtual Machine: java的调试功能最终是由VM负责实现的。back-end: 主要职责是通信,把调试请求从debugger前端发送到VM,再把response返回回去。debugger后端与前端通信是基于JDWP协议。
- communication channel: debugger后端与debugger前端之间的连接,包含2个组件。connector: 通过connector建立连接。connector分三类:listening connector, attaching connector, launching connectortransport: 负责底层数据交换,可以用的transport有sockets, serial lines, 和 shared memory。
- front-end: 负责实现JDI接口
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123217-1979509755.png)
JPDA只是定义了接口规范 ,需要具体实现,才能实现java调试。
Oracle JDK 针对这3个接口,提供了参考实现,具体包含:
- 在VM上实现了JVM TI 接口
- 一个debugger back-end 实现(使用了JVM TI接口,实现了JDWP协议的debuggee一端)
- 一个debugger front-end 实现(使用了JDWP协议的debugger一端的功能,实现了JDI接口)
- 2个简单的基于JDI的调试工具,即jdb。
JDK提供的参考实现
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123265-1842951355.jpg)
JPDA是分层架构设计,其中的每一层都是可以替换的。调试工具可以基于JDI开发,也可以基于JDWP开发,或直接基于JVM TI开发。
Java中的调试功能的实现步骤
- VM提供调试服务,例如提供API用于设置断点,取消断点,设置watch point,单步执行、查看stack frame等。
- VM把调试功能封装成API,通过JVM TI接口的形式提供给调用方。
- debugger后端程序通过调用JVM TI获得调试信息或设置调试动作,然后按照JDWP协议进行封装,实现远程调试。
- debugger前端按照JDWP协议调用debugger后端功能,把功能封装成JDI接口。
- 调试工具,例如IntelliJ IDEA中的debugger,直接调用JDI实现调试功能。
4. Java虚拟机工具接口 (JVM TI)
JVM TI (Java Virtual Machine Tool Interface) 是一个本地编程接口(C++),主要给工具开发商使用,例如像Eclipse、IntelliJ IDEA这样的工具。JVM TI 可以实现的功能有:
- 查看Java应用程序内部状态
- 控制Java应用程序的执行
- 查看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。
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123212-1530596832.jpg)
2. Connector创建好之后launch或者attach到target vm。
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123633-611665957.jpg)
3. 设置event,例如ClassPrepareEvent、BreakpointRequest等:
例如设置断点可以创建BreakpointRequest
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123588-1693229260.png)
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123624-1790769753.jpg)
4. 断点触发之后,需要处理BreakpointEvent,例如打印所有变量
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123546-1294155980.jpg)
5. 综合起来
![](https://img2022.cnblogs.com/blog/293583/202208/293583-20220823005123624-1875853487.jpg)
这个例子来自:
http://www.baeldung.com/java-debug-interface
7. 基于JDI开发debugger的示例
JDK的一个子目录(JDK demo包)即 $JDK/demo/jpda 中,有3个JDI接口的使用示例(源码和文档)。
- trace:显示程序执行轨迹。
- jdb:JDK中自带的命令行调试工具。
- javadt:一个简单的GUI调试工具。
java新手自学群 626070845
java/springboot/hadoop/JVM 群 4915800
Hadoop/mongodb(搭建/开发/运维)Q群481975850
GOLang Q1群:6848027
GOLang Q2群:450509103
GOLang Q3群:436173132
GOLang Q4群:141984758
GOLang Q5群:215535604
C/C++/QT群 1414577
单片机嵌入式/电子电路入门群群 306312845
MUD/LIB/交流群 391486684
Electron/koa/Nodejs/express 214737701
大前端群vue/js/ts 165150391
操作系统研发群:15375777
汇编/辅助/破解新手群:755783453
大数据 elasticsearch 群 481975850
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。