調(diào)試心得:通過觀察正常的程序行為來識(shí)別Bug
有時(shí)候,當(dāng)我調(diào)試一個(gè)問題的時(shí)候,我會(huì)特意忽略掉某些線程。
這個(gè)時(shí)候,有人就問了:”這些線程是干什么的?你為什么知道要忽略它們?”
我的回答是:我也不清楚這些線程是干啥的,但是無論它的內(nèi)部工作是什么,這都是正常的?!?/p>
博主 Tess Ferrandez 一直在編寫關(guān)于 CLR 調(diào)試的系列文章,這些文章十分有用,但最為重要的一條是在調(diào)試 ASP.NET 死鎖問題時(shí)該如何忽略掉不相關(guān)的部分。
在實(shí)際項(xiàng)目中,死鎖和掛起這類問題十分難以調(diào)試,因?yàn)槌霈F(xiàn)這類問題時(shí),調(diào)試器中并沒有輸出異常相關(guān)的信息。程序突然之間就停止了響應(yīng),開發(fā)者不得不苦思冥想,到底哪里出錯(cuò)了。
出現(xiàn)此類問題,我們需要先有一個(gè)大概的思路,即:我們需要尋找那些”不同尋常”的東西,而為了找到這類東西,我們首先需要知道,哪些東西是正常的。
舉個(gè)例子,先運(yùn)行程序一段時(shí)間,然后中斷到調(diào)試器,看看內(nèi)存數(shù)據(jù),線程,加載的模塊等相關(guān)信息,并將這些信息記錄下來。你所記錄下的這些信息,就是所謂的”正?!钡某绦蛐袨椋褪钦f,當(dāng)程序正常運(yùn)行的時(shí)候,你所記錄的就是正常的運(yùn)行數(shù)據(jù)。
有了上面的記錄,當(dāng)程序異常的時(shí)候,再次對(duì)比下運(yùn)行時(shí)數(shù)據(jù),就有可能識(shí)別出那些不太正常的數(shù)據(jù)結(jié)構(gòu)了。
當(dāng)調(diào)試一個(gè)大型工程的時(shí)候,可能程序會(huì)啟動(dòng)非常多的線程,你不必知曉每個(gè)線程具體的工作細(xì)節(jié)。例如,當(dāng)我掛接調(diào)試器到一個(gè)目標(biāo)進(jìn)程后,我經(jīng)常會(huì)看到有一些線程會(huì)等待 RPC 對(duì)象或者是內(nèi)核線程池相關(guān)的線程,說老實(shí)話,我也不清楚這些線程是干啥的,但是因?yàn)樗鼈兛偸窃谀抢锴臒o聲息的運(yùn)行著,所以,我也不會(huì)太關(guān)注它們,這些可能就是我上面所說的正常的東西。
總結(jié)
隨著代碼規(guī)模越來越大,診斷機(jī)制需要進(jìn)一步完善,單純通過下斷點(diǎn)調(diào)試可能不是那么有效了,這個(gè)時(shí)候,需要結(jié)合調(diào)試輸出和日志來查找問題。