作為開發人員,掌握開發環境下的調試技巧十分有必要。我們在編寫java程序的過程中,經常會遇到各種莫名其妙的問題,為了檢測程序是哪里出現問題,經常需要增加日志,看變量的值,這樣調試很麻煩。假設我每天花費1小時在調試我的應用程序上的話,那累積起來的話也是很大量的時間。由于這個原因,用這些時間來重視并了解所有使我們調試更方便的功能。那能為你省下一些時間,也將會使你的生活更安逸、輕松。
一、debug視圖
調試中最常用的窗口是:
窗口 | 說明 |
---|---|
debug窗口 | 主要顯示當前線程方法調用棧, 以及代碼行數(有調試信息的代碼) |
斷點breakpoints窗口 | => 斷點列表窗口,可以方便增加斷點,設置斷點條件,刪除斷點等 |
變量variables窗口 | => 顯示當前方法的本地變量,非static方法,包含this應用,可以修改變量值 |
代碼編輯窗口 | => 這個不用多說了 |
輸出console窗口 | => 日志等輸出內容,調試時,可以將關注的組件級別設置低一點,以便獲得跟多輸出信息 |
另外輔助的窗口有:
窗口 | 說明 |
---|---|
表達式expression窗口 | => 寫上自己需要觀察的數據的表達式,或者修改變量值 |
display窗口 | => 可以在display中執行代碼塊,輸出內容等 |
大綱outline窗口 | => 查看當前類的方法,變量等 |
類型層級type hierarchy窗口 | => 查看當前所在類的繼承層次,包括實現接口,類繼承層次 |
方法調用關系call hierarchy窗口 | => 查看當前方法被哪些方法調用,調用方法在哪些類中、第幾行,可以直接打開對應的方法 |
搜索結果search窗口 | => 結合快捷鍵可以查看變量、方法等在工作空間、項目、工作集中被引用或定義的代碼位置 |
1)窗口全覽:
2)debug view(線程堆棧視圖):
debug視圖允許您在工作臺上管理正在調試和運行的程序,他顯示了你正在調試的程序中掛起的線程的堆棧幀,程序中的每個線程作為樹的節點出現。他展示了正在運行的每個目標的進程。如果線程被掛起,它的堆棧幀以子元素的形式展示。以下是一些常用的debug按鈕:
1.表示當前實現繼續運行直到下一個斷點,快捷鍵為f8。
2.表示打斷整個進程
3.表示進入當前方法,快捷鍵為f5。
4.表示運行下一行代碼,快捷鍵為f6。
5.表示退出當前方法,返回到調用層,快捷鍵為f7。
6.表示當前線程的堆棧,從中可以看出在運行哪些代碼,并且整個調用過程,以及代碼行號
詳細介紹:
skip all breakpoints : 將所有斷點設置為被跳過的,設置了skip all breakpoints之后,所有斷點上都會有一個斜線,表示斷點將被跳過,線程不會在該斷點處被掛起。
drop to frame : 這個命令可以讓程序回到當前方法的開頭第一行重新開始執行,可以重新執行這個java堆棧幀,可以選擇一個指定的堆棧幀,然后點擊 drop to frame,這樣就可以重新進入指定的堆棧幀。使用drop to frame時候需要注意:
1.不能drop到已經執行過的方法棧中的方法中。
2.drop到stack frame中時,不會改變全局數據原有的值,比如,一個包含元素的vertor并不會被清空。
step filters : 這個功能比較簡單,就是當我們在debug的時候想要忽略一些我們不關注的類時,可以開啟step filters進行過濾,程序會一直執行直到遇到未經過濾的位置或斷點。step filters功能由use step filters,edit step filters,filter type,filter package四項組成。具體操作如下:
步驟 1: windows -> preferences -> java -> debug -> step filtering.
步驟 2:選擇‘use step filters'
步驟 3:在屏幕上選中所需的選項。你可以添加你自己代碼庫中的部分代碼。
步驟 4:點擊‘apply'
原理上,edit step filter命令用于配置step filter規則,而filter type與filter package分別指的是過濾的java類型與java package。
step return : 跳出當前方法,在被調用方法的執行過程中,使用step return會在執行完當前方法的全部代碼后跳出該方法返回到調用該方法的方法中。
step over : 在單步執行時,在函數內遇到子函數時不會進入子函數內單步執行,而是將子函數整個執行完在停止,也就是把子函數整個作為一步。
step into:單步執行,遇到子函數就進入并且繼續單步執行
resume:恢復暫停的線程,直接從當前位置跳到下一個斷點位置。
suspend:暫停選定的線程,這個時候可以進行瀏覽或者修改代碼,檢查數據等。
eclipse通過suspend與resume來支持線程的暫掛與恢復。一般來講,suspend適用于多線程程序的調試,當需要查看某一個線程的堆棧幀及變量值時,我們可以通過suspend命令將該線程暫掛。resume用于恢復。
有兩種resume需要注意:
第一是當在調試過程中修改程序代碼,然后保存,點擊resume,此時程序會暫掛于斷點。
第二是當程序拋出異常時,運行resume,程序也會暫掛于斷點。
terminate : eclipse通過terminate命令終止對本地程序的調試。
disconnect:eclipse使用disconnect命令來終止與遠程jvm的socket連接。
1、調試執行
標記 | 功能 | 快捷鍵 | 描述 |
---|---|---|---|
6.4 | step info | f5 | -> 單步進入(如果有方法調用,將進入調用方法中進行調試); |
6.4 | step over | f6 | -> 單步跳過(不進入行的任何方法調用中,直接執行完當前代碼行,并跳到下一行); |
6.4 | step return | f7 | -> 單步返回(執行完當前方法,并從調用棧中彈出當前方法,返回當前方法被調用處); |
6.5 | resume | f8 | -> 恢復正常執行(直到遇到下一個斷點); |
7.4 | run to line | ctrl+r | -> 執行到當前行(將忽略中間所有斷點,執行到當前光標所在行); |
6.3 | drop to frame | 無 |
-> 回退到指定方法開始處執行,這個功能相當贊。 在方法調用棧上的某個方法右鍵,選擇drop to frame就可以從該方法的開始處執行 比如重新執行本方法,可以在本方法上用drop to frame,將從本方法的第一行重新執行。 當然對于有副作用的方法,比如數據庫操作,更改傳入參數的對象內容等操作可能重新執行就再是你想要的內容了。 |
6.1+6.2 | copy stack | 無 | -> 拷貝當前線程棧信息 |
如果在調試時,需要排除一些類、包等不需要進入調試,可以使用edit step filters設置。
a6的properties: java進程啟動相關信息,包括控制臺啟動參數,環境參數等。如果參數啟動參數有問題可以先看看這里的實際啟動參數是不是有誤。另外還可以查看虛擬機支持調試的相關選項。
2、數據查看
標記 | 功能 | 快捷鍵 | 描述 |
---|---|---|---|
7.4 | inspect | ctrl+shift+i | -> 察看選擇的變量、表達式的值或執行結果, 再次按ctrl+shift+i可以將當前表達式或值添加到expressions窗口中查看; |
7.4 | display | ctrl+shift+d | -> 顯示選擇的變量、表達式的值或執行結果, 再次按ctrl+shift+d可以將當前表達式或值添加到display窗口中顯示; |
7.4 | execute | ctrl+u | -> 執行選擇表達式; |
7.4 | run to line | ctrl+r | -> 執行到當前行(將忽略中間所有斷點,執行到當前光標所在行); |
7.3 | all instances | ctrl+shift+n | -> 查看選擇的類的所有對象,這個功能超贊; |
7.3 | instance count | 無 | -> 查看選擇的類的所有對象個數; |
7.4 | watch | 無 | -> 添加當前變量、表達式到expressions窗口中; |
3)variables view (變量視圖)
1.為變量名視圖,顯示當前代碼行中所有可以訪問的實例變量和局部變量
2.顯示所有的變量值
3.可以通過該窗口來改變變量值
variables view顯示與debug view中選定的堆棧幀相關的變量信息,調試java程序時,變量可以選擇將更詳細的信息顯示在詳細信息窗格中。此外,java對象還可以顯示出其包含的屬性的值。在該窗口中選中變量鼠標右鍵點擊可以進行許多操作,主要操作有以下這些:
all instances:打開一個對話框來顯示該java類的所有實例,使用該功能需要java虛擬機支持實例的檢索。
all references::打開一個對話框來顯示所有引用了該變量的java對象,
change value::更改變量的值,該功能可以和drop to frame聯合使用進行程序的調試。使用這兩個功能就可以代替重新debug
copy variables:復制變量的值,尤其在變量值很長(比如json數據)的時候,這個功能就派上用場了。
find:有的時候一個類中變量特別多的時候,可以進行查找。
4)breakpoints view (斷點視圖)
1.顯示所有斷點
2. 將當前窗口1中選中的端口失效,再次點擊啟用。
3.異常斷點
breakpoints view將列出你在當前工作區間里設置的所有斷點,雙擊斷點可以進入到程序中該斷點的位置。還可以啟用或禁用斷點,刪除,添加新的,根據工作組或點命中計數給他們分組。在使用斷點是有以下兩個技巧是十分有用的:
hit count: 是指定斷點處的代碼段運行多少次,最典型的就是循環,如果要讓一個循環執行10次就線程掛起,則指定hit count值為10,那么當前的循環執行到第九次的時候就會掛掉。
conditional:顧名思義,就是條件判斷,例如我們需要循環變量i==10時,線程掛起,則條件設定為i==10,選擇suspend when “true”。
那如果上面的hit count和conditional都選擇的話,如果表達式和值設置不合理則會失效。如果選擇suspend when value changes,那么可能在conditional在變量值發生改變的時候就掛起。
5)expressions view (表達式視圖)
1.表達式
2. 點擊此可以新增一個表達式
要在 debug 透視圖的編輯器中求表達式的值,選中設置有斷點的一整行,并在上下文菜單中選擇 inspect 選項。表達式是在當前堆棧幀的上下文中求值的,其結果顯示在 display 窗口的 expressions 視圖中。 比如我想要計算變量a+b的值,那么就可以在表達式視圖中加一個表達式:a+b
6)display view
可以使用這個視圖,輸入或者演算一些新的代碼。這些代碼在當前的調試位置的上下文環境中被執行,這意味著,你可以使用所有變量甚至是內容助手。要執行你的代碼的話,只需標記它,并使用右鍵菜單或者ctrl+u(執行)或者 ctrl+shift+i (檢查)
7)代碼查看輔助窗口
1、代碼視圖:
代碼視圖,用來顯示具體的代碼。其中綠色部分是指當前將要執行的代碼
標記 | 功能 | 快捷鍵 | 描述 |
---|---|---|---|
11.1~11.5 | quick type hierarchy | ctrl+t | 查看當前類、接口的繼承層次, 默認進入時,顯示繼承/實現當前類/方法的子類,子接口11.1;再次ctrl+t,將顯示當前類、接口繼承/實現的超類/接口11.2;調試時,經常用該功能,在接口或抽象類的方法調用處11.3,ctrl+t察看實現類11.4,直接導航到對應的實現方法中11.5。 |
quick outline | ctrl+o | 查看當前類的大綱,包括方法,屬性等內容; 用處不大; | |
open declarations | f3 | 查看變量、屬性、方法定義的地方 |
2、call hierarchy窗口:
標記 | 功能 | 快捷鍵 | 描述 |
---|---|---|---|
12.1~12.2 | open call hierarchy | ctrl+alt+h | 查看方法被調用層次, 可以看當前方法被調用的地方12.1,或者當前方法調用了其他類的方法12.2 |
3、type hierarchy窗口:
標記 | 功能 | 快捷鍵 | 描述 |
---|---|---|---|
13.1~13.4 | open type hierarchy | f4 | 查看繼承層次, 可以查看類的繼承層次,包括子類父類13.1, 或者類實現的接口繼承層次13.2,還會根據選擇的類/接口,在右邊顯示該類的大綱13.3、 13.4; 13.3可以選擇是否顯示父類/父接口的屬性、方法等 |
4、search 窗口:
標記 | 功能 | 快捷鍵 | 描述 |
---|---|---|---|
14.1 | declarations | ctrl+g | 相同的方法簽名在工作空間中及第三方jar包中被定義的位置14.1 |
14.2 | references | ctrl+shif+g | 當前選中的變量、屬性、方法在工作空間中及第三方jar包中被引用的位置14.2 |
14.3 | ctrl+shift+u | 查看變量、屬性 、方法在當前類中出現的地方14.3 | |
14.4 | implements | 查看實現當前接口的類14.8 | |
14.4~14.7 | 顯示方式 | 可以選擇不同的顯示方式,具體看圖 |
二、debug
1.設置斷點
在源代碼文件中,在想要設置斷點的代碼行的前面的標記行處,雙擊鼠標左鍵就可以設置斷點,在相同位置再次雙擊即可取消斷點。有的時候我們還有這樣的需要,就是我并不想一行一行的執行代碼,比如一個for循環會循環1000多遍,我只想在第500遍的時候讓線程掛起進行調試,這個時候我們可以使用條件斷點。 設置條件斷點:我們可以給該斷點設置觸發條件,一旦滿足某條件是才開始調試,可以在斷點處點擊鼠標右鍵,選擇breakpoint properties進入斷點設置頁面,剛剛在講斷點視圖的時候我們學到過hit count和conditional的用法,這里可以設置條件和執行次數。
1.1)斷點類型及斷點窗口
在調試中可以設置的斷點類型有五種:
1.行斷點(line breakpoints) : 條件斷點,顧名思義就是一個有一定條件的斷點,只有滿足了用戶設置的條件,代碼才會在運行到斷點處時停止。
2.方法斷點(method breakpoints ): 方法斷點的特別之處在于它可以打在 jdk的源碼里,由于 jdk 在編譯時去掉了調試信息,所以普通斷點是不能打到里面的,但是方法斷點卻可以,可以通過這種方法查看方法的調用棧。
3.觀察斷點(watch breakpoints-成員變量訪問變更)
4.異常斷點(exception breakpoints)
5.類加載斷點(class load breakpoints)
每種斷點的設置有些許不一樣,可以在斷點上右鍵->breakpoint properties進行設置,但一般在斷點窗口有快速設置的界面,breakpoint properties中多了filter, 其實比較雞肋,用處不大。
斷點相關的快捷鍵:
快捷鍵 | 說明 |
---|---|
ctrl+shift+b | 在光標處大斷點/取消斷點 |
ctrl+alt+b | 忽略所有斷點 |
alt+shift+q, b | 激活斷點窗口 |
1、行斷點: 在方法中的某一行上打斷點1.1、1.4。行斷點可以設置掛起線程/vm的條件1.3,訪問次數1.2。
1.3中的條件是,spring在注冊bean定義(registerbeandefinition)時,如果是org.springframework.demo.mybean,就掛起線程,可以開始單步調試了。
對于命中次數(hit count)1.2的使用,一般是在循環中,第n個對象的處理有問題,設置hit count = n, 重調試時,可以方便到達需要調試的循環次數時,停下來調試。
2、方法斷點:在方法上打斷點2.1、2.2。方法斷點的好處是可以從方法方法進入或者退出時2.3,停下來調試,類似行斷點,而且只有行斷點和方法斷點有條件和訪問次數的設置功能。
但是方法斷點還有另外一個好處,如果代碼編譯時,指定不攜帶調試信息,行斷點是不起作用的,只能打方法斷點。
有興趣的可以通過a1將add line number… 前的勾去掉, 調試下看看。
3、觀察斷點: 在成員變量上打的斷點3.1、3.3。只有對象成員變量有效果,靜態成員變量不起作用。
可以設置變量被訪問或者設置的時候掛起線程/vm 3.2,也就是類似3.4的所有對成員變量的訪問或者設置的方法都會被監控到
4、異常斷點: 異常斷點可以通過4.6添加,或者點擊日志信息中輸出的異常類信息添加。
異常斷點4.1,系統發生異常時,在被捕獲異常的拋出位置處或者程序未捕獲的異常拋出處4.2、4.4, 掛起線程/vm, 也可以指定是否包括異常的子類也被檢測4.3、4.5。
另外除了以上正常設置的異常掛起,從java->debug中可以設置掛起執行,主要有下面兩個:
1、是否在發生全局未捕獲時掛起(suspend execution on uncaught exceptions),調試時,老是有異常掛起影響調試,但是沒有設置異常斷點的情況,就可以勾選掉這個選項;
2、是否在編譯錯誤時掛起,一般在邊調試邊改代碼時會發生這種情況;
另外要提一個的是有main方法啟動的應用,可以在調試配置中勾選stop in main a3, 程序進入時,會掛起線程,等待調試。
5、類加載斷點: 在類名上打的斷點5.1。接口上是打不了類加載斷點的,但是抽象類是可以的,只是在調試的時候,斷點不會明顯進入classloader中,單步進入知會進入到子類的構造方法中,非抽象類在掛起線程后單步進入就會到classloader中(如果沒有filter過濾掉的話)5.3。類加載斷點不管是打在抽象或者非抽象類上,都會在類第一次加載或者第一個子類第一次被加載時,掛起線程/vm5.2。
2.調試程序
1、調試本地 java 語言程序
在所有調試中,調試一個java程序是最簡單的,主要有設置斷點、啟動調試、單步執行、結束調試幾步。
1)設置斷點:
2)啟動調試:eclipse提供四種方式來啟動程序(launch)的調試,分別是通過菜單(run –> debug)、圖標(“綠色臭蟲”)、右鍵->debug as以及快捷鍵(f11),在這一點上,與其他命令(例如run)類似。
彈出提示,需要切換到調試(debug)工作區,勾選“remember my decision”,記住選擇,則下次不再提示,然后點擊【yes】。
3)單步執行:主要使用前面講過的幾個視圖進行調試,其中debug視圖中的幾個按鈕有快捷鍵:
step retuen(f7)
step over (f6)
step into (f5)
結束調試:通過terminate命令終止對本地程序的調試。
二、案例
場景一:小明寫了一個任務執行者,該執行者不間斷的執行一些任務,在現網上運行了一段時間后,發現有概率的出現一些故障,發現運行一段時間后,該任務者異常退出了,退出的因為是空指針,可以小明想要在本地debug,不知道斷點打在哪里,該問題是概率事件,不一定會出現,所以小明debug幾遍下來后,頭暈眼花,連代碼都看不清楚了,小明想要是能有個斷點每當出現空指針異常的時候就停下來讓他發現問題,那該多好呀。
異常斷點
異常斷點:在定位問題的過程中,常常會遇到斷點無法打到合適的位置,以至于和問題的觸發點千差萬別,所以這個時候不妨試試異常斷點,顧名思義,異常斷點是指拋出某種異常后自動掛起的斷點。
點擊紅色部位,增加一個異常斷點
輸入想要定位的異常類型,例如nullpointerexception,這樣系統中拋出任何nullpointerexception異常后,都會掛起當前線程,給你機會去定位問題。
場景二:小明寫了一個巨大的循環,在調測代碼時,小明發現每當循環到第100000次的時候,就是出現問題,沒有達到自己的預期,于是小明在循環里打了個斷點,想看看到底怎么回事,可小明萬萬沒有想到,想要到達100000次循環是多么的困難,小明這個時候已經開始浮想聯翩,如果能有這樣的斷點:
if 循環次數== 100000,線程停下來
條件斷點
如右圖,循環1000次,如果想要在循環到500次的時候停下來,可以創建一個條件斷點,右擊斷點懸著breakpoint properties。
選中enable condition
在空白處,添加你自己的條件,如果條件返回true,線程會被掛起,如果為false,則忽略該異常
hit count為該斷點經過多少次后,正式掛起線程,如果設置為500,則表達前499次,經過該斷點都不會停下,當第500次,該斷點會掛起當前線程。
表達式
表達式可以查看一些在當前代碼中沒有的命令行,方便定位問題。
場景三:小明最近遇到一個難題,在調用一個第三方插件時總是會有問題,小明懷疑是第三方插件的bug,但小明沒有找到源碼不能進行debug,小明該怎么辦呢?
debug定位第三方插件的問題
1.使用反編譯工具將代碼反編譯
2.將反編譯后的源碼進行過濾
3.修復源碼編譯錯誤
4.進行debug
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/u011781521/article/details/55000066