沒有摧毀一切的靈丹妙藥,也沒有確保萬無一失的程序我們應(yīng)該如何捕捉Go程序錯誤我想學(xué)生們的第一反應(yīng)是記日記
但是錯誤記錄的能力是有限的第一,日志是開發(fā)者在代碼中定義的打印信息,我們不能保證日志信息能包含所有的錯誤其次,當(dāng)圍棋程序出現(xiàn)恐慌時,我們不能總是通過recover來捕捉它
在線圍棋程序突然莫名其妙崩潰后,當(dāng)日志記錄沒有覆蓋錯誤場景時,有沒有其他方法可以查看。
存儲器內(nèi)容更新
核心轉(zhuǎn)儲也稱為核心轉(zhuǎn)儲簡單來說就是程序意外終止時產(chǎn)生的內(nèi)存快照我們可以通過核心轉(zhuǎn)儲文件調(diào)試程序,找出它崩潰的原因
在linux平臺上,可以通過ulimit —c命令查看核心轉(zhuǎn)儲配置,系統(tǒng)默認(rèn)為0,表示沒有開啟核心轉(zhuǎn)儲記錄功能。
$ulimit—c0
您可以使用ulimit —c命令來指定記錄核心轉(zhuǎn)儲文件的大小,即打開核心轉(zhuǎn)儲記錄當(dāng)然,如果計算機(jī)有足夠的資源來避免核心轉(zhuǎn)儲的丟失或記錄不完整,也可以執(zhí)行ulimit —c unlimited,而不限制核心轉(zhuǎn)儲的文件大小
那么如何在Go程序中打開core dump呢。
哥特雷斯貝克
我們在您真的理解字符串和字節(jié)之間的轉(zhuǎn)換嗎一文中討論了字符串到字節(jié)的神奇魔力,如下例所示。
packagemainimportfuncstring 2 bytesbytesh:=)BH:=反射SliceHeaderData:噓數(shù)據(jù),Len:shLen,Cap:噓Len,return*(*byte)(不安全
不能修改字符串當(dāng)我們通過黑魔法將字符串類型改為byte,并試圖修改其值時,程序會出現(xiàn)recover無法捕捉到的錯誤
$ gorunmain . gounexpectedfaulttaddress 0x 106 a6 a4 fatal error:faultgoroutine 1(running):runtime . throw(0x 106 a68 b,0x 0)/usr/local/go/src/runtime/panic . go:1198+0x 71 FP = 0xc 00092 ee 8 sp = 0xc 00092 EB 8 PC = 0x 102 bad1 runtime . sigpanic/usr/local/go/src/runtime/signal _ UNIX . go:732+0x 1修改(...)/Users/SLP/github/post demo/core demo/main . go:21 main . main/Users/SLP/github/post demo/core demo/main . go:25+0x 5a FP = 0xc 000092 f 80 sp = 0xc 00092 f 38 PC = 0x 105 b 01 runtime . main/usr/local/go/src/runtime/proc . go:255+0x 227 FP = 0xc 000092 fe0 sp = 0x c0
堆棧信息由GOTRACEBACK變量控制,該變量有五個級別。
無,不顯示goroutine堆棧信息。
默認(rèn)級別Single顯示當(dāng)前的goroutine堆棧信息。
All,顯示用戶創(chuàng)建的所有g(shù)oroutine堆棧信息。
System,它顯示所有由user+runtime創(chuàng)建的goroutine堆棧信息。
崩潰,這與系統(tǒng)打印相同,但會生成一個核心轉(zhuǎn)儲文件。
如果我們將GOTRACEBACK設(shè)置為system,當(dāng)程序崩潰時,我們將看到所有的goroutine狀態(tài)信息。
$ GOTRACEBACK = systemgorunmain . gounexpectedfaultaddress 0x 106 a6a 4 fatal error:faultgoroutine 1(running):runtime . throw(0x 106 a68b,0x0)...go routine 2(forcegc(idle)):runtime . go park(0x0,0x0,0x0,0x0,0x 0)...createdbyruntime . init . 7/usr/local/go/src/runtime/proc . go:294+0x 25 gorroutine 3(GCsweepwait):runtime . go park(0x0,0x0,0x0,0x0,0x 0)...createdbyruntime . GC enable/usr/local/go/src/runtime/MGC . go:181+0x 55 goroutine 4(GCscavengewait):runtime . go park(0x0,0x0,0x0,0x0,0x 0)...createdbyruntime . GC enable/usr/local/go/src/runtime/MGC . go:182+0x 65 exit status 2
如果希望獲得核心轉(zhuǎn)儲文件,應(yīng)該將GOTRACEBACK的值設(shè)置為crash當(dāng)然,我們也可以通過runtime/debug包中的SetTraceback方法來設(shè)置堆棧打印級別
深入調(diào)試
Delve是用Go語言編寫的Go調(diào)試器,我們可以通過dlv core命令調(diào)試core dump。
首先,用下面的命令安裝delve
或者以上面的例子為例,我們通過設(shè)置GOTRACEBACK為崩潰級別來獲取核心轉(zhuǎn)儲文件。
$樹└──main.go$ulimit—cunlimited$gobuildmain.go$gotraceback=crash./main...已中止$tree
此時,在同一個目錄中獲得了核心轉(zhuǎn)儲文件core。
用dlv調(diào)試器調(diào)試核心文件,執(zhí)行命令格式dlv核心可執(zhí)行文件名稱核心文件。
$dlvcoremaincoreType ' help ' for listofcommands。
命令goroutines獲取所有與goroutines相關(guān)的信息。
dlv)go routines * go routine 1—用戶:。/main . go:21 main . main(0x45b 81a)(thread 18061)goroutine 2—User:/usr/local/go/src/runtime/proc . go:367 runtime . go park(0x 42 ed 96)(forcegc(idle))goroutine 3—User:/usr/local/go/src/runtime/proc . go:367 runtime . go park(0x 42 ed 96)(GCsweepwait)goroutine 4—User:/usr/local
Goroutine 1是一個有故障的Goroutine,通過命令goroutine 1切換到它的堆棧幀。
goroutine 1 switched from 1 to 1(thread 18061)dlv)
執(zhí)行命令bt查看當(dāng)前堆棧幀的詳細(xì)信息。
Bt 00x 00000000000454 BC 1 inruntime . raiseat/usr/local/go/src/runtime/sys _ Linux _ 64 . s:16510x 0000000000452 f 60 inruntime . system stack _ switch at/usr/local/go/src/runtime/ASM _ 64 . s:35020 0x 000000000042 c 530 inruntime . fatalstrowat/usr/local/go
通過50x 000000000045 b 81 ain main . modify找到錯誤代碼所在的函數(shù),通過執(zhí)行命令frame 5進(jìn)入函數(shù)的具體代碼。
dlv)frame 5gt,runtime . raise/usr/local/go/src/runtime/sys _ Linux _ 64 . s:165(PC:0x 454 BC 1)警告:debuggingooptimizedfunctionframe 5:。/main . go:21(PC:45b 81a)16:17:18:func modify19:a:= " hello " 20:b:= string 2 bytes(a)= gt,21:b(0)= ' H ' 22:23:24:funcmain25:Modify26:dlv)
此后案件得到解決,問題在于任意修改string的底值。
不能使用Mac。
需要注意的是,上面core dump生成的例子是在linux系統(tǒng)下完成的,mac amd64系統(tǒng)做不到。
這是因為mac系統(tǒng)下的Go限制了核心轉(zhuǎn)儲文件的生成,在Go source src/runtime/signal _ UNIX . Go中有解釋
//go:nosplitfuncscrash//osxcoredumpsarelineeardumpsofthememory,//from the first virtualbytetothelast,withzerosinthegaps//因為ofthewawearrangeaddressspaceon 64位系統(tǒng),//這意味著osxcorefile將是128 gbandeveonazippy//workstation cantakeosxwelloveranhourtowrite(不可中斷)
核心轉(zhuǎn)儲文件是操作系統(tǒng)提供的利器,是程序意外終止時產(chǎn)生的內(nèi)存快照有了core dump,可以更好的恢復(fù)程序崩潰后的事故現(xiàn)場,為故障排除保駕護(hù)航
當(dāng)然,核心轉(zhuǎn)儲文件的生成也有缺點核心轉(zhuǎn)儲文件很大,所以如果在線服務(wù)本身占用了大量內(nèi)存,那么生成核心轉(zhuǎn)儲文件就要耗費(fèi)大量內(nèi)存和時間另外,我們經(jīng)常安排服務(wù)守護(hù)進(jìn)程如果我們的程序頻繁崩潰重啟,會產(chǎn)生大量的核心轉(zhuǎn)儲文件,從而導(dǎo)致磁盤滿的風(fēng)險(如果釋放內(nèi)核限制ulimit —c unlimited)
最后,如果我們擔(dān)心錯誤日志不能幫助我們定位Go代碼問題,我們可以為它打開核心轉(zhuǎn)儲功能,并將印第安納瓊斯添加到修復(fù)程序中對于帶有守護(hù)程序的服務(wù),建議設(shè)置ulimt —c大小限制
鄭重聲明:此文內(nèi)容為本網(wǎng)站轉(zhuǎn)載企業(yè)宣傳資訊,目的在于傳播更多信息,與本站立場無關(guān)。僅供讀者參考,并請自行核實相關(guān)內(nèi)容。