没有摧毁一切的灵丹妙药,也没有确保万无一失的程序我们应该如何捕捉Go程序错误我想学生们的第一反应是记日记
但是错误记录的能力是有限的第一,日志是开发者在代码中定义的打印信息,我们不能保证日志信息能包含所有的错误其次,当围棋程序出现恐慌时,我们不能总是通过recover来捕捉它
在线围棋程序突然莫名其妙崩溃后,当日志记录没有覆盖错误场景时,有没有其他方法可以查看。
存储器内容更新
核心转储也称为核心转储简单来说就是程序意外终止时产生的内存快照我们可以通过核心转储文件调试程序,找出它崩溃的原因
在linux平台上,可以通过ulimit —c命令查看核心转储配置,系统默认为0,表示没有开启核心转储记录功能。
$ulimit—c0
您可以使用ulimit —c命令来指定记录核心转储文件的大小,即打开核心转储记录当然,如果计算机有足够的资源来避免核心转储的丢失或记录不完整,也可以执行ulimit —c unlimited,而不限制核心转储的文件大小
那么如何在Go程序中打开core dump呢。
哥特雷斯贝克
我们在您真的理解字符串和字节之间的转换吗一文中讨论了字符串到字节的神奇魔力,如下例所示。
packagemainimportfuncstring 2 bytesbytesh:=)BH:=反射SliceHeaderData:嘘数据,Len:shLen,Cap:嘘Len,return*(*byte)(不安全
不能修改字符串当我们通过黑魔法将字符串类型改为byte,并试图修改其值时,程序会出现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堆栈信息。
默认级别Single显示当前的goroutine堆栈信息。
All,显示用户创建的所有goroutine堆栈信息。
System,它显示所有由user+runtime创建的goroutine堆栈信息。
崩溃,这与系统打印相同,但会生成一个核心转储文件。
如果我们将GOTRACEBACK设置为system,当程序崩溃时,我们将看到所有的goroutine状态信息。
$ 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
如果希望获得核心转储文件,应该将GOTRACEBACK的值设置为crash当然,我们也可以通过runtime/debug包中的SetTraceback方法来设置堆栈打印级别
深入调试
Delve是用Go语言编写的Go调试器,我们可以通过dlv core命令调试core dump。
首先,用下面的命令安装delve
或者以上面的例子为例,我们通过设置GOTRACEBACK为崩溃级别来获取核心转储文件。
$树└──main.go$ulimit—cunlimited$gobuildmain.go$gotraceback=crash./main...已中止$tree
此时,在同一个目录中获得了核心转储文件core。
用dlv调试器调试核心文件,执行命令格式dlv核心可执行文件名称核心文件。
$dlvcoremaincoreType ' help ' for listofcommands。
命令goroutines获取所有与goroutines相关的信息。
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)
执行命令bt查看当前堆栈帧的详细信息。
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找到错误代码所在的函数,通过执行命令frame 5进入函数的具体代码。
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系统下完成的,mac amd64系统做不到。
这是因为mac系统下的Go限制了核心转储文件的生成,在Go source src/runtime/signal _ UNIX . Go中有解释
//go:nosplitfuncscrash//osxcoredumpsarelineeardumpsofthememory,//from the first virtualbytetothelast,withzerosinthegaps//因为ofthewawearrangeaddressspaceon 64位系统,//这意味着osxcorefile将是128 gbandeveonazippy//workstation cantakeosxwelloveranhourtowrite(不可中断)
核心转储文件是操作系统提供的利器,是程序意外终止时产生的内存快照有了core dump,可以更好的恢复程序崩溃后的事故现场,为故障排除保驾护航
当然,核心转储文件的生成也有缺点核心转储文件很大,所以如果在线服务本身占用了大量内存,那么生成核心转储文件就要耗费大量内存和时间另外,我们经常安排服务守护进程如果我们的程序频繁崩溃重启,会产生大量的核心转储文件,从而导致磁盘满的风险(如果释放内核限制ulimit —c unlimited)
最后,如果我们担心错误日志不能帮助我们定位Go代码问题,我们可以为它打开核心转储功能,并将印第安纳琼斯添加到修复程序中对于带有守护程序的服务,建议设置ulimt —c大小限制
郑重声明:此文内容为本网站转载企业宣传资讯,目的在于传播更多信息,与本站立场无关。仅供读者参考,并请自行核实相关内容。
我省的征兵工作起步于10元,8元。 2022年海南省招考阶段已经结束8月,8元从省考试局获悉,省考试局将开通10元... [查看详情]