Debug控

 

我是一个debug控,很少写单元测试(不是我不想写),每次写完代码我都要把我的代码debug走一遍,这样才放心,debug也是我阅读别人代码的利器,同时我也经常用它来调试错误。 

 

因为上家公司是做CS程序的,本地debug很方便, serverclient启动也不是很慢,所以用debug调试和开发是一件很方便的事情。新公司是做互联网的,在本地debug调试机子承受不起,这对于我这个喜欢debug的人来说,总感觉不舒服,于是有了下面的内容。

远程debug

编译参数支持

除了程序员编写的程序对应的字节码之外,class文件中还包含有大量的调试信息,这些信息是用于记录每一个JVM指令对应着怎样的代码,每个变量的声明位置,以及每个函数调用、数值计算对应的源代码中的行号。所以,我们必须在编译的时候加上“-Ddebug=true”参数,让编译器保留debug信息,如果使用的maven编译,可以在maven环境变量上添加。

JVM启动参数支持

修改你要远程debug机子的JVM的启动参数,加上:“-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=n”;开始看到网上说的什么maven参数,我以为修改maven环境变量,一想不对,因为maven只有在它的生命周期内使用的JVM,真正运行JVM的是servlet/web容器。我使用的是resin,所以我在resin bin目录下修改httpd.sh文件即可。

eclipse设置参数

打开debug configuration,如图所示:


remote java application新建一个debug,如图所示:


填写如下参数:


Name可以随便填,只是一个名称ID

Project要选对,你想看debug哪个源代码工程就选哪个,如果选错的话,debug找不到对应的类,就会出现source not found错误。

Connection type,连接类型选attach,而不是listen,这是一个相反的概念。

Host就是10.3.20.139,这是你要远程debug服务器的IP地址。

Port,应该是socket阻塞的端口,在JVM里(实际应用中是web/servlet容器,由它来启动JVM)配置什么这里就填什么,这里已经配置好了是4000

填完之后直接debug即可。

 

注意:由于javadebug框架能够看到所有线程的状态(eclipse 3.6debug还提供了阻塞整个JVM的功能),而且是基于socket端口方式(shared memory 方式请参考http://www.ibm.com/developerworks/cn/java/j-lo-jpda1/index.html),为避免冲突,一次只能有一个connection,也就是如果有一个attach上了,其他人就attach不上了。

还有一点就是,其他机子上的操作也会触发断点的阻塞,也就是说如果你attach上了,你就拥有了远程JVM的所有行为,别人的请求也会反映到你的断点上。这就要求我们最好只在自己正在开发的地方打断点,不要在公共入口处打断点,不然别人还以为是性能限制呢。

Debug的好处

能够时刻跟踪代码的执行流程,不用为了看分支走向或者看一个对象在运行时的状态写那么多log了。

 

Debug有一个线程列表,打了断点能够看到线程栈,一个方法调用就是一个栈帧,它为我们提供了一个线程里详细的方法调用顺序,利于我们理解源代码,也利于调试错误(可以打一个异常点,JVM发生异常之前会阻塞)。

 

另外,就算远程attach上了,eclipse可能还是很卡,因为它必须保持跟服务器端的连接,而且要处理一些调试信息,这时候可以对服务器优化一下,因为如果是作为内部测试机的话,可以把连接数目什么的限制一下。

Debug热加载

昨天弄了一个本地resin,然后采用远程debug的方式调试,结果我发现我修改方法里的code也能即时生效,我很郁闷,因为我是采用eclipse exporting war方式部署到webapps里的,我在eclipse修改了代码,最多也是编译到指定的目录,为什么能在resin里即时生效呢?我查看了webapps下面的class文件,发现它一直没有变,这就是说它直接修改的是内存中的数据,而且,只有在debug模式下才可以即时生效,到底是为什么呢?

 

在网上找到一些资料,以作记录:

HotSwap“HotSwap”JPDAJava Platform Debugger Architecture)中的一个特性,JPDA增强是自Java 2 SDK1.4新增的功能。HotSwap允许将JVM中的类定义替换为新的类定义,这就允许开发人员在debug时,将修改过的class替换JVM中旧有的class,无需重新启动服务器。不过,目前HotSwap只支持对方法body的修改,不支持对类和方法签名的修改(比如修改类名,方法名,方法参数等)。考虑这些限制,也是有理由的,替换类定义,就需要新类和旧类之间有一个关联,这里关联就是类的全名(或许还有其他信息),类名都改了,就不知道替换哪个类了。至于方法签名的修改,应该是考虑到运行时方法的调用,通过方法签名替换已有的方法调用。 

 

关于热部署、热加载和概念:

热部署:容器状态在运行时重新部署整个项目。这种情况下一般整个内存会清空,重新加载,这种方式可能会造成sessin丢失等情况。tomcat 6确实可以热部署了,而且会话也没丢。
热加载:Debug模式支持热加载。容器状态在运行时重新加载改变编译后的类。在这种情况下内存不会清空,sessin不会丢失,但容易造成内存溢出,或者找不到方法。 

=========================================================================================

2011年8月2日添加

 

在网上看到很多人说jrebel可以实现新增java类和方法也无需重启应用服务器即可生效的功能,包括添加jar包、修改hibernate配置文件等等,于是我下了一个破解版,然后在jvm启动时添加如下启动参数-noverify -javaagent:<yourpath>/jrebel.jar,一开始就发现一个显著的缺点,因为它监视着WEB-INF/classesclasspath等,所以必须把修改之后的class文件放在对应的目录下,jrebel才检测得到进而采取热加载,而不像debug模式那样,直接替换内存中的方法body。另外,刚开始修改了方法body,更新WEB-INF/classes下面的class文件,jrebel重新检测到并装载,但是第二次新建了一个public的字段和一个方法,就不行了,不知道是我配置不对,还是它确实不像传言中能够实现新增java类和方法也能即时生效。

 

最后,不知道有人用过jetty吗?配合JEE版本的eclipse不知道能不能实现新增java类和方法也无需重启应用服务器即可生效的功能??

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值