使用JDB调试Java程序

Java程序中有逻辑错误,就须要使用JDB来进行调试了。调试程序在IDE中很方便了,好比这篇博客介绍了在Intellj IDEA中调试Java程序的方法。html

咱们课程内容推荐在Linux环境下学习,有同窗问如何在命令行下调试Java程序,咱们就要使用JDB了。java

学习建议:Linux Bash下打开三个标签页

咱们提倡在Linux命令行下学习Java编程。学习时在Ubuntu Bash中经过Ctrl+Shift+T快捷键打开三个标签(tab),:一个使用vim编辑代码;一个使用javac, java(或ant, gradle...)编译运行代码;一个使用JDB调试代码。linux

以下图所示,这样就不用在一个窗口中进行编辑,编译运行和调试的切换了,能提升效率。web

如上图, 咱们在Linux Bash中输入 vim HelloJDB.java编辑调试示例代码:算法

1 public class HelloJDB {
2   public static void main(String[] args) {
3       int i = 5;
4       int j = 6;
5       int sum = add(i, j);
6       System.out.println(sum);
7           
8       sum = 0;
9       for(i=0; i< 100; i++)
10          sum += i;
11          
12      System.out.println(sum);
13  }
14      
15  public static int add(int augend, int addend){
16      int sum = augend + addend;
17      return sum;
18  }
19}

代码编辑完,咱们按“:w”进行保存而不是“:wq”进行保存退出,这样在编译或调试中遇到问题就能够按Alt+1 进入第一个标签修代码了。编程

咱们按Alt+2 进入第二个标签,使用javac -g -d bin src/HelloJDB.java对程序进行编译。注意javac中-g参数是为了产生各类调试信息,必定要加上,不然没法调试。vim

咱们按Alt+3 进入第三个标签,使用jdb -classpath .:./bin HelloJDB对程序进行调试。
windows

调试基础

调试程序先要学会设置断点,这样才能让程序停在你感受有问题的代码处进行排查。学习调试咱们要学会设置四种断点:api

  • 方法断点
  • 行断点
  • 条件断点
  • 临时断点

咱们在JDB中输入help能够查看命令列表:bash

上图中的stop in 用来设置方法断点,stop at 设置行断点。学习过程当中要常常查看帮助文档。
上图汉化有个错误,stepi下面的下一步应该是next命令,这两个都是单步执行命令,咱们后面会解释stepnext的区别。

咱们经过运行stop in HelloJDB.main命令在main方法开始处设置断点:

如上图,咱们输入run命令来运行HellJDB.class,程序会在main()的开始处停下。

此时能够用locals命令查看变量,用step命令运行下一行代码:

看两条locals命令的结果,开始只有main方法的参数args,后面就有局部变量i,j的值了。

不使用locals命令,咱们可使用printeval命令来查看变量的值:

咱们可使用list来查看运行到了源代码的什么位置,HelloJDB.class文件和HelloJDB.java不在同一个文件夹下,咱们须要使用usesourcepath指出源代码的位置,下图中的箭头指出代码运行到了哪一行:

你们注意上图是将要运行第五行,但尚未运行。还要注意,第五行是个方法调用。咱们继续输入steplist,咱们发现代码跳入16行方法体中了:

通常说来,调试时遇到方法调用,咱们先看调用结果对不对,结果正确,说明方法没有问题,就不用进入方法体了; 方法调用结果不对,咱们才须要进入方法体进行调试。单步跟踪命令nextstep在执行通常语句时没有区别,在执行有方法调用的语句时,next会把方法执行完,step
会进入方法体。因此在调试时,单步执行咱们要优先使用next,这样效率比较高。

如今已经进入方法体了,咱们能够运行step up把方法执行完,返回调用处,后面执行通常语句,你发现nextstep没有区别。

第九行和第十行是个循环,这两条语句单步执行起来有点费劲。

咱们能够经过stop at HelloJDB:12在第12行设个断点,而后运行cont就会一会儿把循环运行完并停在第十二行。cont是continue的缩写,功能是运行到下一个断点处中止。

咱们能够用stopclear命令查看设置的断点的状况。

其实这里最好用个临时断点,还有,若是第9行问题出在i=80处,咱们就须要条件断点,惋惜JDB不支持临时断点和条件断点。

咱们使用quitexit能够退出JDB。

类的调试

递归的学习

递归算法是一种直接或间接地调用自身的算法。在编写程序时,递归算法对解决一大类问题是十分有效的,它每每使算法的描述简洁并且易于理解。

递归用于解决形式相同,规模不一样的问题,能用递归解决的问题均可以转化为循环。递归把一个大型复杂的问题层层转化为一个与原问题类似的规模较小的问题来求解,递归策略只需少许的程序就可描述出解题过程所须要的屡次重复计算,大大地减小了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序每每十分简洁易懂。

递归程序有两个要点:递归公式和结束条件。咱们以求整数的阶乘为例:

有了公式,代码就容易写出来了:

1 public class Factorial {
  2     public static void main(String [] args) {
  3         System.out.println(fact(5));
  4     }
  5
  6     public static int fact(int n) {
  7         if (n == 0)
  8             return 1;
  9         else
 10             return n * fact(n-1);
 11     }
 12 }

fact(5)的递推过程以下图:

咱们设置好断点:

方法调用一次就会造成一个栈帧,咱们在JDB中用where显示栈帧,用up,down能够在栈帧之间跳转。

你们用up,down 体会一下压栈,出栈:

多线程的调试

Java API的学习

JDB 不可是个好的调试工具,也是一个好的学习工具,可让你了解程序的动态执行过程。

其余

JDB没有GDB那么强大,若是想使用GDB调试Java代码,以参考用GDB 调试Java程序

参考资料


欢迎关注“rocedu”微信公众号(手机上长按二维码)

作中教,作中学,实践中共同进步!

rocedu



若是你以为本文对你有帮助,请点一下左下角的“好文要顶”和“收藏该文