在工作中,经常遇到项目在生产系统遇到问题,而在测试环境或者开发环境不能复现,这时候一个重要的方法就是要在生产系统进行调试,这里调试分为两种:
- 使用开发工具(eclipse)进行远程调试;
- 使用jdb进行远程调试,或服务器(生产系统)端调试;
首先介绍一下jdb,jdb即java debugger,是随jdk发布的java命令行调试工具,什么情况下需要用jdb工具进行调试呢?比如,客户不在本地,或者没有条件赶赴客户现场,客户现场只能提供一个远程桌面环境(如:teamview获取qq远程),这样就不能将开放工具连接到生产系统,只能通过jdb这样的命令行调试工具。
以上两种调试方式,不管采用哪一种,都需要在tomcat的启动脚本中设置JVM虚拟机参数,以便是tomcat JVM虚拟机工作在debug模式:
-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
或者:
-Xdebug -Xrunjdwp,transport=dt_socket,server=y,address=5432,suspend=n,onthrow=java.io.IOException,launch=/sbin/echo
transport指定了调试数据的传送方式,dt_socket是指用SOCKET模式,另有dt_shmem指用共享内存方式,其中,dt_shmem只适用于Windows平台(windows平台使用jdb调试时,只能用dt_shmem方式,用eclipse远程调试则不限)。
server参数是指是否支持在server模式的VM中.
onthrow指明,当产生该类型的Exception时,JVM就会中断下来,进行调式。该参数可选。
launch指明,当JVM被中断下来时,执行的可执行程序。该参数可选
suspend指明,是否在调试客户端建立起来后,再执行JVM。
onuncaught(=y或n)指明出现uncaught exception 后,是否中断JVM的执行.
虚拟机参数设置
1.启用调试服务
-Xdebug 启用调试
-Xrunjdwp:<sub-options> 加载JVM的JPDA参考实现库
2.Xrunjdwp子参数(sub-options)配置
Xrunjdwp子参数的配置格式如下
-Xrunjdwp:<name1>[=<value1>],<name2>[=<value2>]...
几个例子
-Xrunjdwp:transport=dt_socket,server=y,address=8000
在8000端口监听Socket连接,挂起VM并且不加载运行主函数直到调试请求到达
-Xrunjdwp:transport=dt_shmem,server=y,suspend=n
选择一个可用的共享内存(因为没有指address)并监听该内存连接,同时加载运行主函数
-Xrunjdwp:transport=dt_socket,address=myhost:8000
连接到myhost:8000提供的调试服务(server=n,以调试客户端存在),挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_shmem,address=mysharedmemory
通过共享内存的方式连接到调试服务,挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_socket,server=y,address=8000,
onthrow=java.io.IOException,launch=/usr/local/bin/debugstub
等待java.io.IOException被抛出,然后挂起VM并监听8000端口连接,在接到调试请求后以命令/usr/local/bin/debugstub dt_socket myhost:8000执行
-Xrunjdwp:transport=dt_shmem,server=y,onuncaught=y,launch=d:\bin\debugstub.exe
等待一个RuntimeException被抛出,然后挂起VM并监听一个可用的共享内存,在接到调试请求后以命令d:\bin\debugstub.exe dt_shmem <address>执行,<address>是可用的共享内存
对于tomcat来说,以上参数不用设置,因为tomcat的启动脚本里都已经设置好了,我们只需要使用启动脚本,并指定脚本的启动参数,就可以让TOMCT已DEBUG模式启动:
./catalina.sh jpda start;tail -f ../logs/catalina.out
启动后,tomcat进程会在8000端口监听调试程序。
启动JDB调试
jdb [ options ] [ class ] [ arguments ]
对于使用jdb进行远程调试,这里只介绍jdb的基本用法,命令格式如下:
jdb -attach ip:port -sourcepath <dir1:dir2....>
-attach 指要挂接到一个已经存在的JVM进程上
ip是远程(或本地)JVM所在服务器的ip,如果是本地,可以省略此参数;
port,即JVM启动参数中,address参数指定的端口;
--sourcepaht 可以指定多个源代码根路径,如果不指定,则默认是.
此命令执行完,正常情况会挂载到指定的JVM,并进入jdb提示符:
root@ausun:~# jdb -attach 192.168.0.172:8000
设置未捕获的java.lang.Throwable
设置延迟的未捕获的java.lang.Throwable
正在初始化jdb...
>
可以开始输入jdb命令,主要命令如下:
设置断点
stop at MyClass:22 (在MyClass第22行源代码的第一个指令处设置一个断点)
stop in java.lang.String.length (在java.lang.String.length方法的开始位置设置一个断点)
stop in MyClass.<init> (<init>标识MyClass的构造函数)
stop in MyClass.<clinit> (<clinit>标识MyClass的静态初始化代码)
clear MyClass:45 清除断点,也可以用不指定参数的clear命令,清除之前设置的所有断点。
步进
step 命令用于向前执行到当前栈帧或被被调用方法的下一行
next 命令用于向前执行到当前栈帧的下一行。
cont 继续运行,跳到下一个断点,或者运行下去。