《Effective Debugging:軟件和系統調試的66個有效方法》一第5條:在能夠正常運作的系統與發生故障的系統之間尋找差別...

本節書摘來自華章出版社《Effective Debugging:軟件和系統調試的66個有效方法》一書中的第1章,第1.5節,作[希]迪歐米迪斯·斯賓奈里斯(Diomidis Spinellis),更多章節內容可以訪問云棲社區“華章計算機”公眾號查看

第5條:在能夠正常運作的系統與發生故障的系統之間尋找差別

我們通常都能夠同時訪問這樣兩個系統,其中一個是發生故障的系統,另一個是與之相似但卻可以正常運行的系統。當我們實現了某項新功能、更新了某些工具或基礎組件,或是把系統部署在某個新的平臺上面時,就可能會遇到新系統無法正常運行的問題,此時如果舊系統依然正常,那么我們通常可以通過尋找(下面就會講到如何尋找)或盡量縮小(參見第45條)新舊兩個系統之間的差別來鎖定問題的原因。
之所以能根據新舊系統間的差距來進行調試,其原因在于:盡管各人所經歷的問題有所不同,但計算機的底層運作方式卻是十分確定的,也就是說,同樣的輸入會產生同樣的輸出。因此,只要能夠深入故障系統中,并對其進行足夠的探查,我們就遲早能夠找到相關的bug,從而揭示出該系統為什么會在行為上與正常系統有所不同。
其實有很多時候,系統的故障原因都會非常明確地出現在你面前,只要你肯打開程序的日志文件(參見第56條),就有可能發現里面有一條消息告訴你,clients.conf這個配置文件有錯誤:
image

在另外一些情況下,錯誤的原因可能會隱藏得比較深,此時你必須提升系統日志的詳細程度(verbosity),才能把它暴露出來。
如果系統沒有提供足夠詳細的日志機制,那我們就需要用追蹤工具來梳理其運行時的行為。除了DTrace和SystemTap等通用的工具,還有一些專門的工具可以用來追蹤對操作系統的調用(strace、truss、Procmon)、對動態鏈接庫的調用(ltrace、Procmon)、網絡包(tcpdump、Wireshark)以及SQL數據庫調用(參見第58條)。有很多Unix應用程序(如R Project)是借助復雜的shell腳本來啟動的,因此可能會以極其隱晦的方式出錯。針對這樣的錯誤,在大多數情況下,我們都可以通過給相應shell傳入-x選項的辦法來進行追蹤,這樣得到的數據通常很龐大,所幸現在的系統都有很大的容量能夠存放這兩份日志(以其中一份表示那個可以正常運作的系統,另一份表示出現了故障的系統),而且都有很強的CPU能夠對其進行處理與比較。
就系統的操作環境而言,我們應該盡量確保這兩個系統擁有相似的環境,因為這樣能夠更加方便地對比日志文件或追蹤信息,有時甚至可以直接找到造成bug的原因。我們可以先從一些較為明顯的部分入手,例如,程序的輸入以及命令行參數等。與早前所說的原則一樣,我們也要親自進行驗證,而不能想當然地接受假設。例如,應該在兩個系統的輸入文件之間進行對比,如果它們都比較龐大并且離得比較遠,那可以考慮對比它們的MD5校驗和。
然后,我們應該把重點放在代碼上。首先對源代碼進行對比,我們可能要挖得深一些才能找到bug所在的地方。可以通過ldd命令(適用于Unix系統)或是帶有/dependents選項的dumpbin命令(適用于Visual Studio)來查看與每個可執行文件有關的動態程序庫,并通過nm命令(適用于Unix系統)、帶有/exports/imports選項的dumpbin命令(適用于Visual Studio)或javap命令(適用于以Java語言開發出來的程序)來查看程序所定義和使用的符號。如果你確信問題肯定出現在代碼中,但又看不出明顯的差別,那么可能就要往更深的層次去探查了,也就是需要對比由編譯器所生成的匯編代碼(參見第37條)。
然而在進行更深層次的探查之前,應該先考慮一下有沒有其他因素會影響程序的執行情況,環境變量就是這樣一個容易忽視的因素,即便是沒有特權的用戶,也依然可以通過設置環境變量來破壞程序的正常執行。另一個因素是操作系統。與運行著正常程序的那個操作系統相比,故障程序所在的這個操作系統,可能新了10年或是舊了10年。此外,也要考慮編譯器、開發框架、第三方鏈接庫、瀏覽器、應用程序服務器、數據庫系統以及其他一些中間件。至于怎樣在這么多的因素中確定問題的根源,則是我們接下來要講的話題。
大多數情況下,我們都是在一堆干草里面找一根針(大海撈針),因此應該盡量使這堆干草變得小一些,于是,就要花時間來構造一個既能體現bug,又最為簡單的測試用例(參見第10條)。(另外一種辦法是把要找的針變大一些,也就是命令這個有bug的程序輸出更多的信息,然而這種做法很少能起到比較好的效果。)簡明的測試用例可以縮短日志文件與追蹤信息的長度并減少處理時間,從而令調試工作變得更加輕松。要想有條理地簡化測試用例,我們可以在確保能夠重現bug的前提下,逐漸刪除用例中的元素或系統中的配置選項,直到刪至最簡。
如果正常系統和故障系統的區別位于源代碼中,那么有一種很實用的辦法,就是對這兩個版本之間的歷次修改進行二分搜索(binary search),以確定問題所在。例如,如果正常系統的版本號是100,而故障系統的版本號是132,那我們首先測試116版的程序是否正常,如果116版正常,那就判斷它與132版之間的中點,也就是124版是否正常,如果116版有錯,則判斷它與100版之間的中點,也就是108版是否正常,并依此類推。每次修改完程序之后,我們都應該把代碼單獨提交到版本控制系統里面,這樣做的好處之一,就是使得我們能夠進行二分搜索。某些版本控制系統提供了可以自動執行搜索的命令,例如,Git就提供了git bisect命令(參見第26條)。
還有一個很有效的辦法,是用Unix工具對比兩份日志文件(參見第56條),以找出其中與bug有關的區別。我們在這種情況下所使用的工具,是diff命令,它可以顯示出兩份文件的不同之處。然而日志文件經常會在無關緊要的地方表現出差別,這會把那些與bug真正有關的差別給掩蓋掉,于是,我們可以考慮用各種辦法來過濾干擾因素。例如,如果每一行開頭的幾個字段,都是時間戳與進程ID等信息,那我們就可以用cut或awk命令來把這些大同小異的信息裁掉。下面這條命令可以對Unix系統的messages日志文件進行裁切,它會從每一行的第4個字段開始顯示其內容:
image

只把你感興趣的那些事件選出來就可以了,例如,如果你只對打開的文件感興趣,那么可以用grep'open('這樣的命令來進行篩選。你也可以用grep-v gettimeofday等命令來把對自己有干擾的文本行過濾掉(例如,在Java程序里面,會有成千上萬次與獲取系統時間有關的調用)。此外,還可以在sed命令中指定適當的正則表達式,以便把文本行中自己不感興趣的那一部分裁掉。
最后再講一個高級的實用技巧:如果兩份文件各自的排序方式無法使diff命令給出有效的對比結果,那我們可以把感興趣的字段提取出來,對其進行排序,然后用comm工具在排好順序的兩個集合中找尋不同的元素。例如,如果我們想對比t1和t2這兩份追蹤信息,以找出有哪些文件只出現于t1中,那么可以在Unix的Bash shell中輸入下列命令,它會在包含字符串open(的那些文本行里面提取表示文件名的第二個字段,并在提取出來的這兩個集合之間尋找差別:
image

兩對小括號里面的那兩個元素,會分別生成兩份有序列表,列表中的每一項都是一個傳給open的文件名,而comm命令(這個命令用來在兩份列表之間尋找共同的元素)則以這兩份列表為輸入值,并把只出現在第一份列表中的內容列出來。
要點
在能夠正常運作的系統與出現故障的系統之間對比,找出行為上的區別,以求發現故障的原因。
影響系統行為的所有因素都要考慮到,包括代碼、輸入、調用時的參數、環境變量、服務以及動態鏈接庫。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/456590.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/456590.shtml
英文地址,請注明出處:http://en.pswp.cn/news/456590.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何安裝多個Python版本以及在Pycharm中切換Python版本

目錄前言: 首先要切換不同的版本,你必須先下載不同的Python版本,整個步驟如下所示:1、下載Python2.7x和Python3.5x版本2、安裝Python2.7x和Python3.5x版本3、配置環境變量,分別添加如下至path路徑4、只修改Python27&am…

【python】邏輯運算符總結

# 邏輯運算符 &#xff1a;構造復雜條件 # 優先級 not > and > or # 邏輯與 and 并且、同時 import random# a random.randint(1,5) # if a > 1 and a < 3_流程控制: # print("true") # else: # print("false") # 可以轉換為假&#…

C#中out和ref之間的區別【轉】

首先&#xff1a;兩者都是按地址傳遞的&#xff0c;使用后都將改變原來參數的數值。 其次&#xff1a;ref可以把參數的數值傳遞進函數&#xff0c;但是out是要把參數清空&#xff0c;就是說你無法把一個數值從out傳遞進去的&#xff0c;out進去后&#xff0c;參數的數值為空&am…

如何打開.ipynb文件

最近碰到文件名后綴為.ipynb文件&#xff0c;起初沒太在意這種文件格式&#xff0c;用Notepad打開之后看到也是類似于JSON格式的信息&#xff0c;以為也是為其他的一些文件服務的&#xff08;類似于配置一些HTML文件的配置文件&#xff09;。但是后來才發現這也是一種文本表示形…

《CCNP TSHOOT 300-135認證考試指南》——2.9節憑記憶完成表格和列表

本節書摘來自異步社區《CCNP TSHOOT 300-135認證考試指南》一書中的第2章&#xff0c;第2.9節憑記憶完成表格和列表&#xff0c;作者 【加】Raymond Lacoste , 【美】Kevin Wallace&#xff0c;更多章節內容可以訪問云棲社區“異步社區”公眾號查看 2.9 憑記憶完成表格和列表CC…

將f2fs文件系統到磁盤

1 用git下載f2fs文件系統tools的源代碼。下載地址如下&#xff1a;http://git.kernel.org/cgit/linux/kernel/git/jaegeuk/f2fs-tools.git 具體的操作如下&#xff1a;git clone git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git 通過以…

【python】list append()和extend()區別

list append() ---》添加一個對象整體 extend() ----》添加迭代的對象 append() 添加單一元素在末尾 my_list [geeks, for] my_list.append(geeks) print(my_list) output: [geeks, for, geeks]添加一個list后&#xff0c;也是只添加一個list對象 my_list [geeks, for…

玩Python遇到的問題一二三及解決辦法

文章目錄問題一&#xff1a;python 2.7版本解決TypeError: encoding is an invalid keyword argument for this function。問題二&#xff1a;python讀取文件時提示"UnicodeDecodeError: gbk codec cant decode byte 0x80 in position 205: illegal multibyte sequence&qu…

《MATLAB圖像處理超級學習手冊》導讀

前言 MATLAB圖像處理超級學習手冊圖像是人類獲取信息的重要來源。當今的信息化社會&#xff0c;對圖像處理和圖像分析的要求越來越高&#xff0c;現有的圖像軟件由于采購成本和功能的限制&#xff0c;已經不能完全滿足專業人士的需要&#xff0c;這時就需要專業人士來編寫自己的…

【python】SOCK_STREAM和SOCK_DGRAM兩種類型的區別【轉】

sock_stream 是有保障的(即能保證數據正確傳送到對方)面向連接的SOCKET&#xff0c;多用于資料(如文件)傳送。 sock_dgram 是無保障的面向消息的socket &#xff0c; 主要用于在網絡上發廣播信息。 SOCK_STREAM是基于TCP的&#xff0c;數據傳輸比較有保障。SOCK_DGRAM是基于U…

JavaScript將字符串中的每一個單詞的第一個字母變為大寫其余均為小寫

要求&#xff1a; 確保字符串的每個單詞首字母都大寫&#xff0c;其余部分小寫。 這里我自己寫了兩種方法&#xff0c;或者說是一種方法&#xff0c;另一個是該方法的變種。 第一種&#xff1a; function titleCase(str) {var newarr,newarr1[]; newarr str . toLowerCase() .…

聊天機器人的分類及綜述

文章目錄[toc] 目錄前言&#xff1a;1、技術方向2、chatbot的知識框架3、應用的分類4、chatbot的幾個challenges5、工業應用綜述總結&#xff1a;目錄 前言&#xff1a; 最近由于工作需要&#xff0c;要開發一款智能客服&#xff0c;目前正在搞業務咨詢模塊的功能&#xff0c…

【python】數據結構和算法 + 淺談單鏈表與雙鏈表的區別

有這么一句話說“程序數據結構算法”&#xff0c;也有人說“如果把編程比作做菜&#xff0c;那么數據結構就好比食材&#xff08;菜&#xff09;&#xff0c;算法就好比廚藝&#xff08;做菜的技巧&#xff09;”。 當然這是籠統的說法&#xff0c;不過也稍微懂得了數據結構和…

Ironic 安裝和配置詳解

轉自&#xff1a;http://amar266.blogspot.com/2014/12/ironic-installation-and-configuration.html 1.Install Openstack With Neutron 2.Create and delete vm to test the setup 3.Configure existing setup for ironic 3.1.Configure ironic user in keystone # keystone …

webpack使用優化(基本篇)

轉自&#xff1a;https://github.com/lcxfs1991/blog/issues/2 前言 本文不是webpack入門文章&#xff0c;如果對webpack還不了解&#xff0c;請前往題葉的Webpack入門&#xff0c;或者阮老師的Webpack-Demos。 為什么要使用Webpack 與react一類模塊化開發的框架搭配著用比較好…

word2vec中單詞向詞向量的轉換過程詳解

目錄前言&#xff1a;1、Word2Vec兩種模型的大致印象2、CBOW模型流程舉例3、CBOW模型流程舉例總結&#xff1a; 目錄 前言&#xff1a; 針對word2vec是如何得到詞向量的&#xff1f;這篇文章肯定能解決你的疑惑。該篇文章主要參考知乎某大神的回答&#xff0c;個人在此基礎上…

Python把函數作為參數傳入的高階編程方法

map:接受兩個參數&#xff08;函數&#xff0c;Iterable&#xff09;&#xff0c;map將傳入的函數依次作用于Iterable的每個元素&#xff0c;并且返回新的Iterable def f(x):return x*x r map(f,[1,2,3,4]) #此時的r為惰性求值——可用next()和for...in取值 #通過list()返…

《編程珠璣(第2版?修訂版)》—第2章2.2節無處不在的二分搜索

本節書摘來自異步社區《編程珠璣&#xff08;第2版?修訂版&#xff09;》一書中的第2章2.2節無處不在的二分搜索&#xff0c;作者【美】Jon Bentley&#xff0c;更多章節內容可以訪問云棲社區“異步社區”公眾號查看。 2.2 無處不在的二分搜索我想到的一個數在1到100之間&…

JavaScript學習筆記(四)——jQuery插件開發與發布

jQuery插件就是以jQuery庫為基礎衍生出來的庫&#xff0c;jQuery插件的好處是封裝功能&#xff0c;提高了代碼的復用性&#xff0c;加快了開發速度&#xff0c;現在網絡上開源的jQuery插件非常多&#xff0c;隨著版本的不停迭代越來越穩定好用&#xff0c;在jQuery官網有許多插…

AIML元素詳細說明

目錄前言&#xff1a;1、簡介2、詳細說明總結&#xff1a; 目錄 前言&#xff1a; 智能客服客戶咨詢功能的實現主要依靠的就是Python的AIML庫&#xff0c;這里就先介紹下AIML。 詳細的使用教程可參考&#xff1a;https://github.com/andelf/PyAIML 目前大部分AIML只支持Py…