写过 C/C++ 的都是到,调试程序的时候通常使用 gdb 工具来进行调试,用起来可爽了,那么 gdb 是否也适合 golang 程序的调试呢?
我个人到是通常使用 dlv 来进行 golang 程序的调试,分享一波。
dlv全称 Delve,Delve 可以让你通过控制程序的执行来与程序进行交互,他可以计算变量,并提供线程 / goroutine 状态、CPU 寄存器状态等信息。
Delve 的目标是为调试 Go 程序提供一个简单强大的调试功能。
尝试看一下 dlv 的 help 信息
Usage:dlv[command]AvailableCommands:attachAttachtorunningprocessandbegindebugging.connectConnecttoaheadlessdebugserver.coreExamineacoredump.dap[EXPERIMENTAL]StartsaheadlessTCPservercommunicatingviaDebugAdaptorProtocol(DAP).debugCompileandbegindebuggingmainpackageincurrentdirectory,orthepackagespecified.execExecuteaprecompiledbinary,andbeginadebugsession.helpHelpaboutanycommandrunDeprecatedcommand.Use'debug'instead.testCompiletestbinaryandbegindebuggingprogram.traceCompileandbegintracingprogram.versionPrintsversion.
通过 help 我们可以看到可以使用这些命令来调试我们的程序,根据不同的应用场景
例如,我们直接编译并调试的时候就可以使用 dlv debug
调试一个正在运行的程序,就可以使用 dlv attach
调试一个编译好的二进制文件,可以使用 dlv exec
其他的使用方式也类似,看上述的英文大概就知道啥意思了
开始调试小程序
简单写一个小程序来应用一下这个调试工具
constNUM=10funcmain(){arr:=make([]int,NUM)fori:=1;i<NUM;i++{arr[i]=i+ifmt.Printf("arr[%d]==%d\n",i,arr[i])}fmt.Println("programover")}
1、使用 dlv debug main.go 开始调试
>dlvdebugmain.goType'help'forlistofcommands.(dlv)
2、dlv 里面使用 help 查看一下可以使用哪些命令
这些命令对应的解释相对还是比较清楚的,我们可以来用一下
3、使用 break
打给 main 函数一个端点,或者是用 b
(dlv)bmain.mainBreakpoint1setat0xef84eaformain.main()d:/mycode/my_new_first/dlvtest/main.go:7
给 main 函数打 1 断点,断点号是 1
4、continue
继续执行代码,直到运行到 main 的中断
(dlv)c>main.main()d:/mycode/my_new_first/dlvtest/main.go:7(hitsgoroutine(1):1total:1)(PC:0xef84ea)2:3:import"fmt"4:5:constNUM=106:=>7:funcmain(){8:arr:=make([]int,NUM)9:10:fori:=1;i<NUM;i++{11:arr[i]=i+i12:fmt.Printf("arr[%d]==%d\n",i,arr[i])
5、再 打一个断点,加上具体的条件
b
文件:行数
condition
中断号 具体的条件
(dlv)bmain.go:12Breakpoint2setat0xef85a4formain.main()d:/mycode/my_new_first/dlvtest/main.go:12(dlv)condition2i==7
6、continue
继续执行代码
(dlv)carr[1]==2arr[2]==4arr[3]==6arr[4]==8arr[5]==10arr[6]==12>main.main()d:/mycode/my_new_first/dlvtest/main.go:12(hitsgoroutine(1):1total:1)(PC:0xef85a4)7:funcmain(){8:arr:=make([]int,NUM)9:10:fori:=1;i<NUM;i++{11:arr[i]=i+i=>12:fmt.Printf("arr[%d]==%d\n",i,arr[i])13:}14:fmt.Println("programover")15:}
7、locals
查看本地变量信息 , p/print
打印变量信息
(dlv)localsarr=[]intlen:10,cap:10,[...]i=7(dlv)args(noargs)(dlv)pi7(dlv)parr[]intlen:10,cap:10,[0,2,4,6,8,10,12,14,0,0]
使用 p
查看多个变量的信息,打印出具体的值
8、bp/breakpoints
查看中断列表 , clear
清空中断
查看中断列表
清空其中一个中断
再查看中断列表看看效果
(dlv)bpBreakpointruntime-fatal-throw(enabled)at0xe6ca00forruntime.throw()c:/programfiles/go/src/runtime/panic.go:1107(0)Breakpointunrecovered-panic(enabled)at0xe6cc80forruntime.fatalpanic()c:/programfiles/go/src/runtime/panic.go:1190(0)printruntime.curg._panic.argBreakpoint1(enabled)at0xef84eaformain.main()d:/mycode/my_new_first/dlvtest/main.go:7(1)Breakpoint2(enabled)at0xef85a4formain.main()d:/mycode/my_new_first/dlvtest/main.go:12(1)condi==7(dlv)clear2Breakpoint2clearedat0xef85a4formain.main()d:/mycode/my_new_first/dlvtest/main.go:12(dlv)bpBreakpointruntime-fatal-throw(enabled)at0xe6ca00forruntime.throw()c:/programfiles/go/src/runtime/panic.go:1107(0)Breakpointunrecovered-panic(enabled)at0xe6cc80forruntime.fatalpanic()c:/programfiles/go/src/runtime/panic.go:1190(0)printruntime.curg._panic.argBreakpoint1(enabled)at0xef84eaformain.main()d:/mycode/my_new_first/dlvtest/main.go:7(1)
9、ls
查看当前代码运行的位置 ,next
执行源码的下一行
(dlv)ls>main.main()d:/mycode/my_new_first/dlvtest/main.go:12(hitstotal:0)(PC:0xef85a4)7:funcmain(){8:arr:=make([]int,NUM)9:10:fori:=1;i<NUM;i++{11:arr[i]=i+i=>12:fmt.Printf("arr[%d]==%d\n",i,arr[i])13:}14:fmt.Println("programover")15:}
constNUM=10funcmain(){arr:=make([]int,NUM)fori:=1;i<NUM;i++{arr[i]=i+ifmt.Printf("arr[%d]==%d\n",i,arr[i])}fmt.Println("programover")}0
通过箭头我们就可以看出来 ,没有毛病
10、bt/stack
打印堆栈信息
constNUM=10funcmain(){arr:=make([]int,NUM)fori:=1;i<NUM;i++{arr[i]=i+ifmt.Printf("arr[%d]==%d\n",i,arr[i])}fmt.Println("programover")}1
查看堆栈信息,可以直接看到汇编里面的具体信息
11、goroutines
查看程序中的协程列表,以及其对应的代码行数
constNUM=10funcmain(){arr:=make([]int,NUM)fori:=1;i<NUM;i++{arr[i]=i+ifmt.Printf("arr[%d]==%d\n",i,arr[i])}fmt.Println("programover")}2
goroutine 执行的时候默认是查看当前协程的信息,上面打印可以知道,总共有 5 个协程,当前打印的协程信息是第 1 个
12、goroutine
显示当前当前协程的具体信息和切换协程
主动切换到 第 2 个协程,并查看当前协程的信息
constNUM=10funcmain(){arr:=make([]int,NUM)fori:=1;i<NUM;i++{arr[i]=i+ifmt.Printf("arr[%d]==%d\n",i,arr[i])}fmt.Println("programover")}3
工具需要用起来才有意义。
好了,本次就到这里。
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是小魔童哪吒,欢迎点赞关注收藏,下次见~