Java JDPA

JDPA 是一个框架, 它定义了 debugger 和 debuggee 是如何交互的, 两端交互的API 和 协议, 并不包含具体的实现. 它包含3部分.

  1. debugger 端的API: JDI (Java Debug Interface)
  2. debuggee 端的API: JVM TI
  3. 连接两端的协议: JDWP

JDPA.png

jdb

jdb 是 JDK 自带的命令行 debugger 端, 是 JDI 的实现.

  1. 它能连接本地和远程的目标 Java 应用, 执行 debug 命令.
  2. 它能连接本地和远程的 core dump 文件, 并获取信息.
  3. 它能启动本地要debug 的Java 应用, 并且debug.

    jdb -connect sun.jvm.hotspot.jdi.SAPIDAttachingConnector:pid=9302
    jdb -connect com.sun.jdi.SocketAttach:port=12306
    jdb -connect sun.jvm.hotspot.jdi.SACoreAttachingConnector:javaExecutable=$JAVA_HOME/bin/java,core=core.20441
    远程的 core dump 需要 jsadebugd. 

jdb 本地启动一个app 的背后

下面本地启动一个需要debug的app, 然后观察 jdb 是如何跟这个app交互的.

$ jdb FreeMemoryExample # 启动 jdb 
$ stop at FreeMemoryExample:8 # 设置断点
$ run # 启动应用. 

打开另外一个窗口, 然后观察如下:

$ jps #查看当前机器的 java 进程
3790574 TTY
3790626 FreeMemoryExample
3793734 Jps #jps 本身

$ sudo lsof -T -p  3790574 | grep 5598 #查看进程 3790574 里面连接的 tcp, 它的55985连到本地 55888
jdb     3790574 supra    6u  IPv6           37707266       0t0      TCP suprabox:55985->localhost:55888
$ sudo lsof -T -p 3790626 | grep 5598 #查看进程 3790626 里面连接的 tcp, 它的55888连到本地 55985
java    3790626 supra    4u  IPv4           37703541       0t0      TCP localhost:55888->suprabox:55985
$ ps aux | grep 3790626 #查看 3790626 的启动命令
supra    3790626  0.1  0.2 7021672 41712 pts/0   Sl+  00:06   0:01 /usr/lib/jvm/java-11-openjdk-amd64/bin/java -Xdebug -Xrunjdwp:transport=dt_socket,address=suprabox:55985,suspend=y FreeMemoryExample
$ ps aux | grep 3790574 #查看 3790574 的启动命令
supra    3790574  0.2  0.4 7619496 65040 pts/0   Sl+  00:06   0:02 jdb FreeMemoryExample

所以, 当运行 jdb FreeMemoryExample 的时候, 其实它调用java 进程另外启动了需要被 debug 的程序,并且建立了 tcp socket 通信.

被启动的进程使用了参数: -Xdebug -Xrunjdwp:transport=dt_socket,address=suprabox:55985,suspend=y

添加 debug 参数启动应用, 并连接

只要在对应的 Java 进程启动的时候, 添加类似如下参数, 就能启动debug 监听端口, 等待准备被连接:

$ java -agentlib:jdwp=transport=dt_socket,server=y,address=12306 FreeMemoryExample #启动应用端
# 更多参数参看: https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html

$ jdb -connect com.sun.jdi.SocketAttach:port=12306 # 启动jdb 并连接
 stop at FreeMemoryExample:8  # 设置断点
 run # 开始运行
 locals #显示本地变量
 where # 显示栈

标签: none

添加新评论