idea 偵錯小心得

2023-03-12 15:00:34

1、為什麼需要Debug

目的:開發過程中 查詢或定位錯誤或者閱讀原始碼

程式執行的結果(4種情況)

情況1:沒有任何bug,程式執行正確!

情況2: 執行以後,出現了錯誤或異常資訊。但是通過 紀錄檔檔案或控制檯 ,顯示了異常資訊的位置。

情況3: 執行以後,得到了結果,但是結果不是我們想要的
情況4: 執行以後,得到了結果,結果大概率是我們想要的。但是多次執行的話,可能會出現不是我們想要的情況。比如:多執行緒情況下,處理執行緒安全問題


2、Debug的步驟

1、新增斷點
2、啟動偵錯
3、單步執行
4、觀察變數和執行流程,找到並解決問題

■ 斷點的新增、取消、檢視

  • 新增/取消某個位置的斷點:點選行號位置

  • 檢視所有斷點:Ctrl + Shift + F8

  • 取消所有斷點: 點選檢視所有斷點,不勾選Java Line Breakpoints

偵錯中的斷點意義:執行到了即生效了,就會暫停一下。

打多個斷點的意義:整個專案也可以打一個斷點,然後執行到想要觀察的方法的呼叫,通過step into 進入觀察,但是可能點快了,直接完執行方法呼叫。但是專案工程比較大,對於想要觀察的方法打上一個斷點,執行到了,它就會生效暫停,暫停一下更方便而已。

■ 設定好斷點後,啟動選擇debug方式啟動:

  • debug 鍵的位置:行號點選三角形可以選擇,程式碼內容空白位置右鍵可以選擇,選單工具列的執行臭蟲子圖示可以選擇

  • 程式碼中的列印、紀錄檔語句,執行後,在Debug模式下Console 觀察

  • 變數區的變數注意是當前方法棧的


3、idea 偵錯快捷鍵


4、總結一下偵錯快捷鍵的使用

(1) 常用的:

觀看下一步的單步偵錯[F8],進入方法體內部[F7],退出方法體,執行下一步[Shift+F8],直接跳到下一個斷點[F9]

(2) 走神了:

回到當前檔案斷點位置[Alt+F10],跳到遊標[Alt+F9],

太走神/觀察不細緻,那就重來一遍:回退到上一個方法呼叫的開始處[Drop Frame]

(3) 結束:

結束偵錯[Ctr+F2]、讓當前斷點後面的所有斷點失效[Mute Breakpoints]


5、偵錯過程的其他小技巧

(1) Ctr+滑鼠

  • 點選目標進入,再次點選,如果不能再進入則會出來。目標可以是屬性物件,也可以是類、是介面,是方法等等。

(2) Alt+箭頭方向←

  • 讓遊標回到上一個遊標位置。有時候,因為Ctr+滑鼠點選進入之後,在不移動遊標位置,想退回上一個遊標位置,那麼Alt+←

(3) 全域性搜尋快捷鍵

  • Ctr+Shift+F

  • Ctr+Shift+N

(4) 定位當前開啟的檔案的位置

  • 定位當前檔案所在專案目錄結構位置:


6、斷點細分(重點:條件斷點、執行緒偵錯)

(1) 方法斷點:

  • 剛進入方法會停頓一下

(2) 欄位斷點:

  • 預設會停頓在欄位值發生改變的位置

(3) ☺ 條件斷點----適合觀察迴圈體的程式碼執行流程

  • 可以在斷點位置,設定暫停的條件,右鍵斷點

(4) 異常斷點:

  • 設定某種異常暫停

(5)☺ 執行緒偵錯:

  • 設定,觀察某個執行緒的執行



7、偵錯實踐和心得總結

舉例分散式專案偵錯,比如有三個應用:admin應用-將任務主體儲存到redis,master應用-將redis任務主體進行執行。其中,master實際上是遠端呼叫了worker應用-去執行任務主體。

(1) 多個應用偵錯觀察執行流程:

  • 要注意流程中應用執行,從A應用執行著到了應用B應用,然後再繼續執行到應用C,偵錯的時候,也要跟著流程切換應用的調式模式。

  • 當A應用debug著,突然卡著的時候,就需要考慮這時候執行流程是不是進入了應用B了,切換到應用B的debug模式觀察一下。

  • 切換到C應用的時候,觀察執行下一步,遲遲不肯進入下一步,考慮是不是A應用是不是得「放行」,B應用執行到下一步,C應用才有資格進行執行。

    舉例:B應用[master應用],斷點停在了呼叫遠端C應用[worker應用]的這一行時候:workerWebservice.execChat(chatExecParam);

    然後,因為是遠端呼叫,如果你還點選下一步,會進入的是B應用的反射底層程式碼,這時候,需要通過打斷點跳到下一個斷點(C應用)的程式碼位置,然後觀察C應用的工作流程,但是C工作,真正想要執行run方法,需要B應用執行到下一步,相當於「放行」。

(2) 打斷點要注意遠端呼叫的程式碼位置不能打,否則專案跑不起來

舉例:在@FeignClient的介面中的方法打了斷點,導致專案啟動失敗。

  • 執行流程:A服務遠端呼叫B服務
// A服務,將chatExecParam 傳送給B服務[worker] 去執行
workerWebservice.execChat(chatExecParam);

// 中間的Fegin負載均衡
@FeignClient("chat-worker")
public interface WorkerWebservice {
    @RequestMapping(value = "/execChat", method = RequestMethod.POST)
    boolean execChat(@RequestBody CrawlerExecParam crawlerExecParam);  //《---在這裡打了斷點,導致A服務啟動失敗 
}

// B服務
@Override
@RequestMapping(value = "/execChat", method = RequestMethod.POST)
public boolean execCrawler(ChatExecParam chatExecParam) {
   workerContext.getThreadPool().execute(new ExecQueueScanRunnable(chatExecParam, masterWebservice));
   return true;
}
  • 錯誤資訊:
2023-03-11 22:45:38.162 [WARN ] [main] com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
2023-03-11 22:45:38.172 [INFO ] [main] com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2023-03-11 22:45:38.855 [WARN ] [main] com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
2023-03-11 22:45:38.866 [INFO ] [main] com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2023-03-11 22:46:30.475 [INFO ] [main] o.s.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
2023-03-11 22:47:43.098 [INFO ] [main] o.s.scheduling.concurrent.ThreadPoolTaskScheduler - Initializing ExecutorService 'taskScheduler'
2023-03-11 22:47:46.228 [INFO ] [main] com.alibaba.nacos.client.naming - initializer namespace from System Property :null
2023-03-11 22:47:46.275 [INFO ] [main] com.alibaba.nacos.client.naming - initializer namespace from System Environment :null
2023-03-11 22:47:46.315 [INFO ] [main] com.alibaba.nacos.client.naming - initializer namespace from System Property :null
  • 分析原因:[▷下次抽空補充!◀]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  • 解決:取消掉在@FeignClient介面下的方法打斷點


(3) idea 卡著不動/debug 執行太慢:

  • 偵錯點選下一步,或者偵錯跳到下一個斷點的時候,idea 卡著不動:

判斷是否卡著:按鍵-結束偵錯是啟用狀態;重要的是在Variables 提示了一句:程式正在執行The application is running

程式真正(debug)結束

  • 原因分析

① 可能原因1:方法斷點會使得正在debug偵錯的程式變慢【建議:少用方法斷點

② 可能原因2:斷點打太多建議儘量不要在專案裡打過多的斷點,偵錯哪裡就在哪裡打上,偵錯完把斷點去掉就好。

③ 可能原因3:執行的方法是遠端方法(和網路有關)或者執行的方式是資料庫操作有關。


☺ 心得總結

1、 建議:少用方法斷點

2、 建議:不要打太多斷點,為了觀察方便,需要再打,觀察完,可以去掉斷點。

3、注意:如果專案是分散式專案,負載均衡@Feign的介面中的方法【 本來就不建議在方法的位置打斷點了! 】,如果影響了專案啟動,請取消斷點。




如果本文對你有幫助的話記得給一樂點個贊哦,感謝!