java调试原理

[quote]
目前可以用来调试Java应用程序的工具令人叹为观止。现代ide提供了全功能的调试界面,并且像glassbox这样的工具用bci(bytecode instrumentation)提供了关于应用程序运行时状态的更多信息。虽然你有时候会发现自己处于无法使用这些工具的境地,或许应用程序被部署在防火墙的另一端,不允许你远程调试;或许你正在客户那里,没有你喜欢的工具可用。现代调试工具使用的大多数信息和方法都由jvm自己提供,并具有控制这种信息而不用最新图形工具的一些方法。本文关注一些可用的调试方法,它们只使用java sdk(jdk)自带的那些工具。

jdb i!\W^udUAX=n3kg`!p [ 本 资 料 来 源 于 贵 州 学 习 网 网络编程Java教程 http://Www.gzU521.com ] i!\W^udUAX=n3kg`!p

jdk携带的主要调试工具是jdb,这是一种命令行调试器,它将附到一个在运行的vm,并允许你设置断点(breakpoint)、逐步跟踪代码、检验变量并评估表达式的值。jre没有包括jdb,因此你需要安装jdk。

如果你知道如何利用ide中内建的任何调试器调试java应用程序,你就可以迅速地学会利用jdb进行调试。为了允许jdb或者任何调试器连接到一个在运行的jvm,jvm必须通过许多命令行参数来启动。这些参数促成jvm去加载和初始化调试库,配置传输并打开一个socket。例如,要配置vm在端口8000监听调试连接,你应该使用类似于下面的命令行选项:

-Xdebug -Xrunjdwp:transport=dt_socket,suspend=n,server=y,address=8000

你现在可以利用下面的命令行用jdb连接:

jdb -attach 8000

或者在windows上:

jdb -connect com.sun.jdi.SocketAttach:port=8000

一旦连接上,你应该看到jdb提示。

你现在连接到了jvm,可以开始调试你的应用程序了。你想要做的第一件事可能是设置一些断点。在jdb中设置断点有三种方法。

1、在命名方法的项上设置断点。
2、在指定的源代码行数上设置断点。
3、在发生特定异常的时候。

当你的应用程序触发断点时,jvm将中止执行,并等待你告诉它接下来要利用jdb做什么。你可以跳过去,进入到方法调用里面,检查本地变量,并评估表达式,为了获得一个可用命令的列表,可以输入help来得到它。

虽然利用jdb调试比用为你显示源代码行的图形调试器更慢,但是只要你访问源代码,就可以获得与利用jdb相同的效果。

不建议你通过调试参数运行产品应用程序,因为使用这些参数的时候,有一个性能和安全问题。但在测试、开发期间以及检查某类产品问题的时候,jdb都是一种非常有用的工具。

关于jdb的更多信息,请见sun的文档:http://java.sun.com/j2se/1.3/docs/tooldocs/win32/jdb.html。

利用thread dump

现代的java和jave ee应用程序有许多线程,它们全都彼此交互,并连接到外部系统。java提供了一种获取在vm中运行的所有线程的调用堆栈快照的方法。这个的输出称作 thread dump,它是大量的堆栈轨迹(每个线程一个),以及关于线程优先级和它持有或等待的任何锁或监视器的信息。

生成thread dump在不同的操作系统中做起来也不同。在windows中,是在jvm运行的控制台窗口中按下ctrl-break。对基于LINUX和unix的系统,则用kill命令将sigquit发送到jvm。这可以通过命令kill – 3 完成,这里的pid是jvm的进程id。

现代的企业java应用程序中,经常有大量的线程,它们中有许多都没起任何作用。你可以用许多种方式来辨别重要的线程。

◆它们通常具有较长的相关堆栈轨迹。
◆搜索已知的包名称(例如你应用程序中使用的包)。SCK&U@m RNRV2!"0m8'[ 此文转贴于我的学习网网络编程Java教程 http://www.Gzu521.com]SCK&U@m RNRV2!"0m8'

线程持有或者等待的任何锁或者监视器都在轨迹中指定,因此死锁以及其他同步相关的问题,都可以通过分析哪些线程在等待或者持有哪些锁和监视器进行辨别。

在性能调优或者调试慢运行应用程序时,它对相隔几秒钟生成许多thread dump并对它们进行比较会很有利。这样让你知道应用程序的哪些部分正在缓慢地运行着,而不必使用更高级的性能分析工具。

jmx

从java se 5开始,sun给jvm运行时信息提供了jmx api作为java se的一部分,sun还提供了一种工具,用来在一个正运行的jvm内部查询mbeans。这个工具是jconsole,并且就像jdb一样,它是与jdk捆绑在一起的。

为了允许jconsole连接到你的vm,你需要增加许多命令行参数。

-dcom.sun.management.jmxremote
-dcom.sun.management.jmxremote.port=20001
-dcom.sun.management.jmxremote.authenticate=false
-dcom.sun.management.jmxremote.ssl=false

当你运行jconsole时,它将在你的机器上侦测vm运行,并问你想要连接到哪一个。一旦你连接上了,摘要(summary)屏幕就会显示大量关于vm的信息,让你访问使用关于它线程的运行时信息、堆的使用(heap usage),以及所有变得能通过jmx mbeans使用的信息。通过将mbeans增加到你的应用程序中,有可能使你的应用程序信息能通过jmx控制台以及用jmx接口收集它们信息的其他工具来使用。利用jmx将监视功能增加到你的应用程序,则是另一篇文章的主题了。

关于使用jconsole的更多信息,请见:http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html。

信息唾手可得

这些工具虽然不完整,或者不像你习以为常的工具那么容易使用,但它们仍然提供了很多你可以用来分析和调试你应用程序的信息。基本熟悉了它们之后,就可以快速解决问题,否则要花数天进行调查,因此值得花时间去体验它们,并了解它们是如何工作的。

http://java.sun.com/j2ee/1.4/docs/devguide/dgdebug.html

http://docs.sun.com/source/819-0079/dgdebug.html

http://www.infoq.com/cn/articles/basic-java-debugging



-----------------------------------------------------------------------------

jdb -connect com.sun.jdi.SocketAttach:port=8000

stop in com.soulinfo.webcomponent.ArchiveBorrow_Component.onInit
stop at com.soulinfo.webcomponent.ArchiveBorrow_Component:154
clear com.soulinfo.webcomponent.ArchiveBorrow_Component.onInit
clear com.soulinfo.webcomponent.ArchiveBorrow_Component:154

run 继续执行
cont 继续执行
next ->执行一行(STEP)
step ->执行一行(STEP INTO)
locals -> 显示局部变量
dump 对象名 ->显示对象信息
print 对象名 ->显示简单对象信息

> help
** 命令列表 **
connectors - 列出此 VM 中可用的连接器和传送器

run [类 [参数]] - 开始执行应用程序的主类

threads [线程组] - 列出线程
thread <线程 ID> - 设置默认线程
suspend [线程 ID] - 暂停线程(默认为所有线程)
resume [线程 ID] - 恢复线程(默认为所有线程)
其中 [<线程 ID> | all] - 转储线程的堆栈
其中 [<线程 ID> | all] - 转储线程的堆栈,以及 pc 信息
up [n 帧] - 向上移动线程的堆栈
down [n 帧] - 向下移动线程的堆栈
kill <线程 ID> <表达式> - 中止具有给定的异常对象的线程
interrupt <线程 ID> - 中断线程

print <表达式> - 输出表达式的值
dump <表达式> - 输出所有对象信息
eval <表达式> - 输出表达式的值(与 print 相同)
set <lvalue> = <表达式> - 为字段/变量/数组元素指定新值
locals - 输出当前堆栈帧中的所有局部变量

classes - 列出当前已知的类
class <类 ID> - 显示已命名的类的详细信息
methods <类 ID> - 列出类的方法
fields <类 ID> - 列出类的字段

threadgroups - 列出线程组
threadgroup <名称> - 设置当前线程组

stop in <类 ID>.<方法>[(参数类型,...)]
- 在方法中设置断点
stop at <类 ID>:<行> - 在行中设置断点
clear <类 ID>.<方法>[(参数类型,...)]
- 清除方法中的断点
clear <类 ID>:<行> - 清除行中的断点
clear - 列出断点
catch [uncaught|caught|all] <类 ID>|<类模式>
- 出现指定的异常时中断
ignore [uncaught|caught|all] <类 ID>|<类模式>
-- 对于指定的异常,取消 "catch"
watch [access|all] <类 ID>.<字段名>
- 监视对字段的访问/修改
unwatch [access|all] <类 ID>.<字段名>
- 停止监视对字段的访问/修改
trace methods [线程] - 跟踪方法输入和退出
untrace methods [线程] - 停止跟踪方法输入和退出
step - 执行当前行
step up - 执行到当前方法返回到其调用程序
stepi - 执行当前指令
next - 跳过一行(跨过调用)
cont - 从断点处继续执行
list [line number|method] - 输出源代码
use(或 sourcepath) [源文件路径]
- 显示或更改源路径
exclude [<类模式>, ...| “无”]
- 对于指定的类,不报告步骤或方法
classpath - 从目标 VM 输出类路径信息

monitor <命令> - 每次程序停止时执行命令
monitor - 列出监视器
unmonitor <监视器号> - 删除监视器
read <文件名> - 读取并执行命令文件

lock <表达式> - 输出对象的锁信息
threadlocks [线程 ID] - 输出线程的锁信息

pop - 弹出整个堆栈,且包含当前帧
reenter - 与 pop 相同,但重新输入当前帧
redefine <类 ID> <类文件名>
- 重新定义类的代码

disablegc <表达式> - 禁止对象的垃圾收集
enablegc <表达式> - 允许对象的垃圾收集

!! - 重复执行最后一个命令
<n> <命令> - 将命令重复执行 n 次
help(或 ?) - 列出命令
version - 输出版本信息
exit(或 quit) - 退出调试器

<类 ID>:带有软件包限定符的完整类名
<类模式>:带有前导或后缀通配符 (*) 的类名
<线程 ID>: "threads" 命令中报告的线程号
<表达式>:Java(TM) 编程语言表达式。
支持大多数常见语法。

可以将启动命令置于 "jdb.ini" 或 ".jdbrc" 之中
(两者位于 user.home 或 user.dir 中)
>
[/quote]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值