掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
本文轉(zhuǎn)載自微信公眾號(hào)「 跨界架構(gòu)師」,作者Zachary 。轉(zhuǎn)載本文請(qǐng)聯(lián)系 跨界架構(gòu)師公眾號(hào)。

大家好,我是Z哥。
可以不夸張地說(shuō),程序員可能有一半的時(shí)間都在修bug。雖說(shuō),根據(jù)28原則大部分bug都可以在搜索引擎上搜到(業(yè)務(wù)性bug除外),但是往往剩下的那20%bug會(huì)花費(fèi)我們80%的時(shí)間。
雖然解決這個(gè)問(wèn)題最好的是方式減少產(chǎn)生bug,但是再怎么減都不可能減到0,我們還是有必要提高自己Debug的效率。
因?yàn)樵贒ebug方面,水平高的人可能在效率上能領(lǐng)先至少一個(gè)數(shù)量級(jí)。我在這個(gè)行業(yè)從業(yè)將近9年,我見過(guò)太多這樣的案例了。網(wǎng)上也流傳過(guò)一個(gè)傳播度很高的案例,有一個(gè)阿里內(nèi)部的團(tuán)隊(duì)排查好幾天未果的一個(gè)問(wèn)題,去請(qǐng)教多隆大神,分分鐘就搞定了。
很多人的Debug能力之所以長(zhǎng)期止步不前,在我看來(lái)主要原因是兩個(gè)。
不同的編程語(yǔ)言,主流的IDE都不同,所以我主要就第二點(diǎn)展開說(shuō)說(shuō)我的經(jīng)驗(yàn)。
有些經(jīng)驗(yàn)的程序員都知道,Debug的過(guò)程最重要的不是怎么修復(fù)bug,而是怎么找到產(chǎn)生bug的地方。所以,下面要講的思路主要也是圍繞排查bug相關(guān)。
縮小問(wèn)題范圍的方式有很多,本質(zhì)上其實(shí)是從當(dāng)時(shí)的環(huán)境中找到與問(wèn)題更高相關(guān)的變量。最常見的變量主要在以下這些:
建議你先從這幾個(gè)變量進(jìn)行驗(yàn)證。然后再弄清楚上一次正常操作與當(dāng)前出現(xiàn)bug的操作之間的這段時(shí)間發(fā)生過(guò)什么。大多數(shù)情況下,問(wèn)題的根源就藏在這里面。那種潛藏很久才遇到的疑難問(wèn)題,畢竟是少數(shù)。
工作中很多流程需要SOP,在修復(fù)bug這件事上也可以這么做,如此可以將每一次修復(fù)一個(gè)疑難bug的過(guò)程給沉淀下來(lái)。
常見的bug類型主要有4類:
每一類都有適合它們的排查方式,如果你總是用同一個(gè)套路去排查這4類問(wèn)題,效率自然不會(huì)太高。
這種bug最頭疼,為什么呢?因?yàn)樗幌衲欠N異常、報(bào)錯(cuò)的bug,有堆棧信息,可以快速縮小排查范圍,甚至直接定位到產(chǎn)生的地方。
那么怎么辦呢?如果這個(gè)問(wèn)題在測(cè)試環(huán)境,那么最簡(jiǎn)單,直接單步調(diào)試走起,這個(gè)時(shí)候如果對(duì)IDE的調(diào)試工具掌握得越深入,效率也會(huì)越高,比如條件變量、多線程調(diào)試等等。
這里多說(shuō)一句,強(qiáng)烈建議每個(gè)人掌握自己所用IDE的條件變量和多線程調(diào)試這兩種方法,在當(dāng)前的大環(huán)境下,整個(gè)軟件開發(fā)領(lǐng)域的大型項(xiàng)目和多線程運(yùn)用都比幾年前高得多。
如果沒法單步調(diào)試的情況,那么只能通過(guò)多打一些日志,來(lái)達(dá)到接近單步調(diào)試的效果。不過(guò)這點(diǎn)需要你做一些預(yù)判,在一些代碼分支、可疑位置打上日志即可,畢竟編寫記錄日志的代碼也需要時(shí)間不是。
這種bug對(duì)有些經(jīng)驗(yàn)的程序員來(lái)說(shuō)是最簡(jiǎn)單了,因?yàn)橹苯痈嬖V了你產(chǎn)生異常的代碼位置。
但是對(duì)新手就不同了,很多新手會(huì)拿著描述異常的一堆文字去搜索引擎搜,比如(NullPointer Exception),搜出來(lái)N多文章,一篇一篇看下來(lái)并嘗試都發(fā)現(xiàn)不能解決自己的問(wèn)題,其實(shí)就是由于自己還沒習(xí)慣于去看堆棧信息。因?yàn)閯e人的NullPointer Exception和你的NullPointer Exception產(chǎn)生的原因并不一樣。
堆棧信息中記錄了整個(gè)調(diào)用鏈路,所以通過(guò)這里你可以看到完整的方法調(diào)用順序。
不過(guò)值得提醒的是,在日常編寫的代碼的時(shí)候,千萬(wàn)不能隨意的try catch代碼塊,然后throw一個(gè)new exception,因?yàn)檫@會(huì)導(dǎo)致堆棧信息不完整。
這種問(wèn)題一般是在產(chǎn)生資源競(jìng)爭(zhēng),或者資源緊張的時(shí)候發(fā)生。排查他們的難度也比較高。
如果說(shuō)前面兩類問(wèn)題中,高水平和低水平的區(qū)別只在于解決效率的高低上,那么這個(gè)問(wèn)題對(duì)低水平的程序員們來(lái)說(shuō)可能是不管花多少時(shí)間都找不到問(wèn)題的原因。
不過(guò)不要緊,我建議你以后遇到這種情況,優(yōu)先從以下這幾個(gè)指標(biāo)入手。
對(duì)于TCP連接,你身邊得常備一份netstat命令手冊(cè),然后敲入命令,分別查看連接數(shù)是否接近到了65535?TIME_WAIT、CLOSE_WAIT狀態(tài)的連接是不是過(guò)多?
大多數(shù)情況下,TCP連接相關(guān)的問(wèn)題主要就是兩個(gè):
對(duì)內(nèi)存問(wèn)題的分析,主要是就是通過(guò)分析GC來(lái)進(jìn)行,主要關(guān)注是否有什么類型的對(duì)象占用內(nèi)存過(guò)大了。如果存在過(guò)大的情況,主要原因是以下兩個(gè):
不同的編程語(yǔ)音有不同的GC分析工具,需要熟練掌握。
對(duì)線程的分析,和TCP連接類似,主要集中在線程的數(shù)量和狀態(tài)上。線程并不是數(shù)量越多、性能就越好。數(shù)量越多,可能花在線程之間的上下文切換上的時(shí)候就比實(shí)際執(zhí)行代碼邏輯還要多。
另外,是不是有大量線程blocked或者deadlocked了?隨便挑其中一個(gè)線程,分析其當(dāng)前的堆棧信息,就是問(wèn)題所在。
導(dǎo)致crash的主要原因有兩點(diǎn)。
第一點(diǎn)參照原因3的處理方式。
第二點(diǎn)就很簡(jiǎn)單了,在代碼的最外層做一個(gè)大大的try catch,然后打上日志將堆棧信息記錄下來(lái),發(fā)布到線上,自然就能看到是那里出現(xiàn)的問(wèn)題,然后轉(zhuǎn)到原因2的處理方式。
最后,提高Debug能力必須要多實(shí)踐。所以,我是非常建議你在條件允許的情況下,勇敢地去挑起排查線上疑難雜癥的任務(wù),甚至并不是你直接負(fù)責(zé)的功能模塊。
可能在外人看來(lái)你在幫別人“擦屁股”,但這會(huì)讓你的Debug能力得到明顯的提升,并且容易形成對(duì)你的依賴,讓你越來(lái)越強(qiáng)。
好了,總結(jié)一下。
這篇呢,Z哥和你分享了我對(duì)提高Debug效率這件事的看法。
想要提高Debug的效率,一是要對(duì)IDE工具有熟練的了解,知道一些高階的使用方式。二是要對(duì)Debug有一套自己的思路。
對(duì)于第二點(diǎn),我建議的步驟是:
Bug主要分為4類,我在文中給出的思路也區(qū)分了這4類:
希望對(duì)你有所幫助。
在我看來(lái),Debug是一件很好玩,也很有成就感的事情,不亞于設(shè)計(jì)一個(gè)項(xiàng)目的框架。而且Debug還能讓你真正地體會(huì)到什么是“魔鬼藏在細(xì)節(jié)里”。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流