使用JDB調試Java程序


Java程序中有邏輯錯誤,就需要使用JDB來進行調試了。調試程序在IDE中很方便了,比如這篇博客介紹了在Intellj IDEA中調試Java程序的方法。

我們課程內容推薦在Linux環境下學習,有同學問如何在命令行下調試Java程序,我們就要使用JDB了。

學習建議:Linux Bash下打開三個標簽頁

我們提倡在Linux命令行下學習Java編程。學習時在Ubuntu Bash中通過Ctrl+Shift+T快捷鍵打開三個標簽(tab),:一個使用vim編輯代碼;一個使用javac, java(或ant, gradle...)編譯運行代碼;一個使用JDB調試代碼。

如下圖所示,這樣就不用在一個窗口中進行編輯,編譯運行和調試的切換了,能提高效率。

如上圖, 我們在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參數是為了產生各種調試信息,一定要加上,否則無法調試。

我們按Alt+3 進入第三個標簽,使用jdb -classpath .:./bin HelloJDB對程序進行調試。

調試基礎

調試程序先要學會設置斷點,這樣才能讓程序停在你感覺有問題的代碼處進行排查。學習調試我們要學會設置四種斷點:

  • 方法斷點
  • 行斷點
  • 條件斷點
  • 臨時斷點

我們在JDB中輸入help可以查看命令列表:

上圖中的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程序 ](http://blog.csdn.net/haoel/article/details/22893
05)。

參考資料


歡迎關注“rocedu”微信公眾號(手機上長按二維碼)

做中教,做中學,實踐中共同進步!

rocedu



如果你覺得本文對你有幫助,請點一下左下角的“好文要頂”和“收藏該文



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM