第七章第四節 調試
防不勝防的bug引入了代碼,如何發現並消除之?編程
Outline
Notes
## 什麼是bug
- bug即程序中的錯誤,致使程序以非預期或未預料到的方式執行。
- 一個包含大量bug和/或嚴重干擾其功能的bug的程序被稱爲buggy。
- 報告程序中的bug一般被稱爲bug報告、故障報告、問題報告、故障報告、缺陷報告等
【bug產生的緣由】框架
- 代碼錯誤
- 未完成的要求或不夠詳細
- 誤解用戶需求
- 設計文檔中的邏輯錯誤
- 缺少文件
- 沒有足夠的測試
【bug的常見類型】工具
- 數學bug:例如 零除法,算術溢出
- 邏輯bug:例如 無線循環和無限遞歸
- 源頭bug:例如 使用了爲被定義的變量、資源泄漏,其中有限的系統資源如內存或文件句柄經過重複分配耗盡而不釋放。緩衝區溢出,其中程序試圖將數據存儲在分配存儲的末尾。
- 團隊工程bug:例如 評論過期或者評論錯誤、文件與實際產品的區別
## 調試的基本過程
- Debug是測試的後續步驟:測試發現問題,debug消除問題;當防護式編程和測試都沒法擋住bug時,咱們就必須進行debug了;
- Debug的目的:尋求錯誤的根源並消除它;(Debug佔用了大量的時間)
【調試的過程】測試
- 經常使用方法:假設-檢驗
- 重現(Reproduce)-->診斷(Diagnose/Locating)-->修復(Fix)-->反思(Reflect)
- 重現(Reproduce):尋找一個可靠、方便得在線需求問題的方法。
- 從最小的測試用例開始復現錯誤(保持復現bug的前提降低低輸入規模)
- 消除因版本、環境、配置等不一樣引發的差別(經過構建軟件實現),肯定bug出現的環境(經過程序模擬硬件平臺的細節,實現不一樣的操做系統環境)
- 利用逆向設計推斷致使錯誤的輸入
- 若沒法重現,則沒法觀察以證實分析和修補的正確性
- 診斷(Diagnose/Locating):構建假設,並經過執行實驗來測試它們,直到您確信已識別錯誤的根本緣由。
- 從假設開始,構造實驗,證實它是對的或者錯的
- 從不符合理論的觀察結果開始,修正理論
- 查看致使錯誤的測試輸入,以及錯誤的結果,失敗的斷言以及由此致使的堆棧跟蹤
- 提出一個與全部數據一致的假設,說明錯誤發生的位置或錯誤發生的位置,設計實驗測試假設
- 收集實驗數據,減小錯誤可能出現的範圍,作出新的假設
- 設計不一樣的實驗:檢查內部狀態、修改運行方式、改變自己邏輯
- 每次只作一個修改、作好記錄、不忽略細節、運行不一樣的測試用例、設置斷點、用可實現相同功能而且被證明無問題的組件替代當前組件
- 修復(Fix):設計和實施解決問題的變化,避免引入迴歸,並保持或提升軟件的總體質量。
- 確保從乾淨的源代碼樹開始
- 運行現有的測試,並證實它們經過
- 添加一個或多個新測試,或修復現有測試,以演示錯誤
- 修復錯誤、發現可改進之處
- 證實你的修復工做正常且沒有引入迴歸(之前經過的測試如今失敗)
- 若是引入迴歸,經過回顧之前的版原本找出確切的變化
- 反思(Reflect):思考需求、設計、測試、結構(庫、編譯器等)

## 調試的技術和工具
【調試技術】操作系統
- 暴力調試(Brute Force Attack)
- 蠻力方法能夠分爲至少三類:
- 看內存導出文件
- 根據「在整個程序中分散打印語句」的常見建議進行調試。
- 自動化調試工具
- 遞歸調試(Induction)
- 演繹調試(Decution)
- 回溯調試(Backtracking)
- 測試調試(Testing)
【調試工具】debug
- 語法和邏輯檢查(本課程未涵蓋)
- 源代碼比較器(Source-code comparator)(參見第2章中的SCM)
- 內存堆轉儲(Memory heap dump)
- 打印調試/日誌記錄(Print debugging / logging)
- 堆棧跟蹤(Stack trace)
- 編譯器警告消息(Compiler Warning Messages)
- 調試器(Debugger)
- 執行分析器(Execution Profiler)(見第8章)
- 測試框架(Test Framework)(見第7-5節)