軟體除錯 (轉)
加入不久,一位久未謀面的朋友問我在做什麼。我說修理工(我在Sybase維護PowerBuilder)。說這話時,我絲毫沒有貶低修理工的意思,相反,我從小就羨慕出色的修理工。不響的收音機,他們搗鼓搗鼓就響了;不幹活的機器,他們鼓搗鼓搗就幹活了。
:namespace prefix = o ns = "urn:schemas--com::office" />
一名出色的除錯(deging)高手是公司的寶貴財富。有一次,有人問公司的一位高階副總裁:誰是他手下最重要的人。回答是:兩名高階工程師,因為有些錯只有他們能解決。在我看來,除錯不光是一種謀生手段,還是一種益智遊戲。所以,在查錯時,千萬不要驚慌,要靜下心來,享受破案的樂趣。
除錯在與維護中佔很大比重。能否儘早、儘快、高質量地除錯關係到軟體的成敗與否。一個開發高手必定是除錯高手。除錯基本上分成兩部分:找出錯誤原因和改正錯誤。怎樣才能定位錯誤原因呢?
1. 熟悉你的工具
工欲善其事,必先利其器。這句成語大家雖然耳熟能詳,但我覺得我們們中國人好象更崇尚不需要任何工具就能辦大事的人,如用一根線就能給人號脈的神醫。但能達到此種境界的究竟有幾人呢?更何況,他們如果有合適的工具,不是能幹得更快更好嗎?
有了好工具,還要挖掘其功能。以而言,它提供了強大的除錯功能。全面掌握其功能,將大大縮短除錯週期。
斷點在除錯中扮演至關重要的角色。合理的設定斷點,能讓你事半功倍。最常用的斷點是位置斷點。執行到斷點時即刻停止。這時,你可以檢查變數的值,檢視的內容等等。寄希望於看到一些蛛絲馬跡。
1.1條件斷點
有時,程式要經過某斷點很多次才能到達你所希望的現場。來回按F5鍵(Go)簡直是不勝其煩。幸好Visual Studio允許我們透過斷點對話方塊為位置斷點設定條件。只有在所設的條件成立時,該斷點才起作用。斷點的條件是一個布林,例如:a==100||(b>10&&c<1.5)。其中a, b, 和c可以是區域性變數、成員變數、也可以是全域性變數。
需要注意的是條件表示式中不能有,包括過載的運算子。那麼,既然不能用strcmp函式,能否讓條件斷點在某一字串變數為某一特定值時起作用呢?能。假設你有一個字串變數str,並希望在str等於“abc”時斷點起作用,你可用如下條件表示式:str[0]==’a’&&str[1]==’b’&&str[2]==’c’。
你還可以讓某一位置斷點跳過若干次後才起作用。假設你正在排除一個GPF。你設定了一個位置斷點,並希望檢視GPF發生之前斷點處的情況。但你不知道要按F5鍵多少次才能到達你所希望的現場。即使你知道按多少次,你也不想按那麼次。幸好,Visual Studio允許一個位置斷點在跳過若干次以後才起作用。你可先讓斷點跳過1000次,然後程式。當機後,看斷點到底跳過多少次才當機。用該次數重新設定斷點的跳躍次數。再執行程式時,程式就會在當機前的一剎那停下來。
1.2資料斷點
在某些場合下,資料斷點會成為你的救星。在查錯時,如果你發現某個資料被莫名其妙地該掉了,怎樣才能查出該資料在何時何地被改掉的呢?用資料斷點。透過斷點對話方塊,給出該資料的地址及長度。以後,在任何程式碼改變該資料的值時,程式就會馬上停下來,讓你分析該變化是否合理。
1.3 Stop always
如果你的程式利用了C++的異常處理功能,在跟蹤時,你有可能發現程式突然跑到一個很遠的catch語句去了。那是因為C++的異常處理功能起作用了。在程式正常執行時,異常處理功能是你的朋友,但在跟蹤時,可就未必了,因為你不知道程式到底在什麼地方出錯了。幸好Visual Studio允許你在跟蹤時取消異常處理功能。選擇Debug—Exceptions選單,在彈出的對話方塊中,改變器(Debugger)在某一類異常發生時所採取的行動(Action)。你可將行動設定成Stop always,只要該類異常發生時,程式馬上停下來。
Visual Studio還提供各種視窗,讓你檢查程式呼叫堆疊、變數、積存器和記憶體等。
1.4其它工具
除了Visual Studio,還要一些很有用的工具,如 NT操作提供的Performance Monitor、Visual Studio的附帶工具Spy++、以及提供的HandleEx、FileMon和RegMon等等。熟練掌握這些工具將對你大有裨益。
2. 熟悉你的程式
有了像樣的工具並不能使你馬上成為除錯高手。一個不懂得機器工作原理的修理工,即使有再好的工具,也很難快速並高質量地修理機器。為什麼在一些大專案中,有些錯只有某幾個人才能排除呢?主要原因是隻有他們才更全面地瞭解他們的程式。
要想成為真正的除錯高手,你要主動出擊,理解程式的總體結構,熟悉程式碼。怎樣才能理解程式總體結構呢?怎樣才算理解了程式總體結構呢?如果你有完備的文件,那算你幸運。如果沒有,那只有憑自己了。我個人的是畫UML圖。有道是“一張圖頂一千句話”。看一眼圖(Component Diagram),馬上就能想到整個程式有哪幾塊組成;看一眼類圖(Class Diagram),馬上就能回想起這幾個類之間的關係;看一眼時序圖(Sequence Diagram),馬上就能想起這幾個是如何互動的。畫圖的工具可以是Rational Rose,也可以是Sybase PowerDesigner,Microsoft Visio,甚至可以是。然後用一個把這些圖串起來,check in到原始檔控制系統( Control System),以便隨時補充修改。
沒有緊急任務時,我會藉助程式碼分析軟體,如SourceNavigator,Source Insight,或 Outline等,概略分析(而不是逐行閱讀),補充所缺的圖。有時,我也會有意識地跟蹤程式,逐個研究函式呼叫堆疊(call stack)中的每個函式,找出類之間的關係並記錄在冊。值得注意的是一定要把你的發現記錄在冊,否則幾個月後,你可能要重新來過。好記性不如爛筆頭子。
另外,查錯的過程也是一個很好的理解原始碼的機會。對那些有重要意義的call stack,我都會記錄下來,以便有空時研究。日積月累,你會發現你不但對總體結構有了深刻理解,而且也掌握了相當多的細節。到這時,查錯就不再是大海撈針,也不是走迷宮,因為你已經有了一張地形圖。
3. 管理的功用
熟練掌握了先進的工具,又對程式有了相當程度的理解,你已經具備了成為除錯高手的條件。而良好的軟體管理能使你事半功倍。軟體管理基本上包括:
l 程式碼控制系統
l 質量跟蹤系統
l 軟體釋出及存檔系統
3.1程式碼控制系統
程式碼控制系統有諸多好處:防止程式碼意外丟失、能保證程式碼同步、允許回溯到開發過程中的任一點、允許多個工程師同時修改同一個檔案等等。由於每一個修改都有記錄,能促使工程師提高程式質量,以免被別人。另外,程式碼控制系統在除錯中也有重要意義。下面將有詳述。
3.2質量跟蹤系統
Sybase有一套相當嚴格的質量跟蹤系統。質量控制工程師、技術支援工程師、甚至是開發工程師都可在質量跟蹤系統中輸入新的錯誤報告(Sybase稱之為change request)。每個錯誤報告都需有詳細的說明、嚴重程度、錯誤復現(reproduce)步驟以及相應的test case等。Test case要儘量小。
每個產品有一個小組,由技術支援經理負責,每週挑選出最嚴重的錯誤,並通知相應的開發小組組長。組長再把錯誤分給相應的工程師。該工程師找出錯誤原因,提出解決方案。方案複查透過後,將經修改的程式碼check in到程式碼控制系統。同時把錯誤報告轉交給質量控制小組。質量控制小組在確認錯誤被解決後,關閉該錯誤報告。
3.3軟體釋出及存檔系統
程式的每一個重要的build都要存檔,可隨時執行。
4. 一些實用技巧
查錯很重要的一環是設定斷點。斷點位置選得好能讓你更快地查出錯誤的原因。這裡有一個小技巧:如果錯誤的表現是程式彈出了一個對話方塊顯示某一出錯資訊,你可以啟動Visual Studio,attach到你的程式,然後選擇Debug—Break選單暫停程式執行。從函式呼叫堆疊上,也許會有所發現。如果程式陷入死迴圈,也可以使用這一技巧。如果錯誤的表現是當機,那就更容易找到切入點了。
在除錯多執行緒(multi-threading)程式時,把程式執行情況寫入檔案中(logging)是一個常用的方法。在你認為有可能出現問題的函式中,把重要資料寫入檔案中。問題出現後,仔細研究該檔案,試圖發現一些蛛絲馬跡。逐漸縮小範圍,知道找出問題之所在。
記憶體洩漏(memory leak)是C++程式的常見問題。檢查記憶體洩漏問題最好要有工具。通常我會先用Performance Monitor證明程式確實發生了洩漏。然後用BoundsChecker或其它工具幫忙確定記憶體洩漏的根源。
有時程式會發生退化(regression),即某一功能突然不工作了。如果不能快速查出原因,我們通常會採用折半查詢(binary search)的方法找出究竟是哪個change list惹的禍。方法是先找出從哪一個build開始出現問題,然後再找出是哪個change list。假設build 1000工作正常,build 1010出現了問題。我們就從程式存檔中下載build 1005,看是否有問題。如果有問題,就下載build 1003,否則下載build 1007。依此類推,直到找出那個build為止。然後從程式碼控制系統中查出這個build與上一個build之間有那些change list,再次採用折半查詢的方法。方法是把程式同步(synchronize)到某個change list,編譯並執行程式,看是否有問題。如此這般,直到找出引起問題的change list。把check in該change list的同事找來一起研究問題的原因並加以解決。
最另人頭痛的錯誤是那些隨機發生、很難再現的錯誤。這些錯誤通常是由於變數未賦初值,或記憶體被破壞等原因造成的。如果程式發生隨機的當機現象,你可以利用Windows提供的SetUnhandledExceptionFilter 函式設定你自己的未處理異常過濾器(unhandled exception filter)。當程式發生未被處理的異常時,Windows會自動呼叫過濾器函式。過濾器函式中,你可以把程式執行現場的情況,如函式呼叫堆疊、暫存器的值等,寫入一個檔案以便分析。如果你的釋出版本(release build)中帶有最基本的除錯資訊,你就能在函式呼叫堆疊中看到真實的函式名稱,而不是密碼一般的函式地址。如果release build中沒有任何除錯資訊,你可從編譯原始檔時生成的map檔案中查出究竟是在執行哪一行程式碼時出現了問題。所以如果你不想讓release build帶除錯資訊,你一定要把map檔案存檔,以備不日之需。
如果你招數用盡,仍無法查出錯誤的根源。你不妨請同事幫忙,或呼叫外部力量。俗話說:沒有過不了的火焰山。只要你不洩氣、群策群力,一定能解決問題。畢竟,是講邏輯的。
錯誤解決後,在大鬆一口氣之前,你最好總結一下查錯的過程及心得。如果你的程式有單元測試程式(unit test),你應該增加一些單元測試程式,防止類似情況再次發生。如果你的程式有自動整合測試,你也應加入相應的測試。
另外,與其被動等錯誤來找你,不如主動出擊。方法之一是進行程式碼複查(code review)。選出某個檔案,由小組成員分頭複查該檔案,然後集體討論,找出所有錯誤及有待提高的地方。程式碼複查不僅能防患於未然,還是提高水平的好招。
態度在除錯中也扮演著重要角色,尤其是在承受著很大的壓力時。由於這個錯誤軟體不能釋出,定單被擱置。但你一定要保持冷靜。“這肯定是的錯”,“這肯定是作業系統的錯”,“這肯定是第三方軟體的錯”等等。說這些話都是不冷靜的。你要“拿證據來”。總之,不要怨天尤人。是自己的錯,勇於承認。是別人的錯,切莫譏諷。
掌握了方法,又有良好的態度,何愁不能成為除錯高手?
5. 參考資料:
《Debugging Applications》
《MSDN》Microsoft
《UML Distilled》Martin Fowler
《Refactoring》Martin Fowler
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-996720/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 筆記|軟體除錯的技巧筆記除錯
- Mac色彩除錯濾鏡軟體Mac除錯
- MacOS 下的 Laravel 除錯軟體 - TinkerwellMacLaravel除錯
- 軟體除錯斷點之小記除錯斷點
- 學習除錯實時嵌入式軟體除錯
- 嵌入式軟體除錯常用知識點除錯
- Windows XP 軟體刪除常見故障(轉)Windows
- PID除錯軟體(C#、模擬、模擬)除錯C#
- 10.3 除錯事件轉存程式記憶體除錯事件記憶體
- Java除錯教程--多執行緒除錯(轉)Java除錯執行緒
- DLL的除錯 (轉)除錯
- 一個不錯的工具軟體--mindmanager(轉)
- 《軟體除錯》讀書筆記:第13章 硬錯誤和藍屏除錯筆記
- perl除錯哲學(轉)除錯
- dbx除錯過程 (轉)除錯
- vc除錯經驗 (轉)除錯
- Bochs 除錯技術(轉)除錯
- 訊息中介軟體RocketMQ原始碼解析-- --除錯環境搭建MQ原始碼除錯
- 訊息中介軟體 RocketMQ 原始碼解析 —— 除錯環境搭建MQ原始碼除錯
- 中介軟體IIS監控指標、配置和Windbg除錯分析指標除錯
- 防禦指南-當你得知你的軟體正在被除錯除錯
- 軟體糾錯
- 軟體、軟體危機、軟體工程 (轉)軟體工程
- 核心除錯神器SystemTap 轉摘除錯
- [轉載]uiautomator埠除錯UI除錯
- NO MFC - 使用 .log 除錯程式 (轉)除錯
- 本地除錯PERL CGI程式(轉)除錯
- 用GDB除錯程式(二) (轉)除錯
- 用GDB除錯程式(四) (轉)除錯
- 用GDB除錯程式(三) (轉)除錯
- 除錯工具TRW2000,VB符號除錯初步(轉)除錯符號
- 除錯篇——除錯物件與除錯事件除錯物件事件
- 讀書筆記之《格蠹彙編-軟體除錯案例集錦》筆記除錯
- 除錯旋轉編碼器成功除錯
- 掌握 Linux 除錯技術(轉)Linux除錯
- 掌握Linux除錯技術(轉)Linux除錯
- Node除錯指南-記憶體篇除錯記憶體
- 記憶體洩漏除錯工具記憶體除錯