翻译原文连接 转帖/转载请注明出处linux
英文原文连接【Go, the unwritten parts】 发表于2017/05/22 做者JBD是Go语言开发小组成员git
检查程序的执行路径和当前状态是很是有用的调试手段。核心文件(core file)包含了一个运行进程的内存转储和状态。它主要是用来做为过后调试程序用的。它也能够被用来查看一个运行中的程序的状态。这两个使用场景使调试文件转储成为一个很是好的诊断手段。咱们能够用这个方法来作过后诊断和分析线上的服务(production services)。github
在这篇文章中,咱们将用一个简单的hello world网站服务做为例子。在现实中,咱们的程序很容易就会变得很复杂。分析核心转储给咱们提供了一个机会去重构程序的状态而且查看只有在某些条件/环境下才能重现的案例。服务器
做者注: 这个调试流程只在Linux上可行。我不是很肯定它是否在其它Unixs系统上工做。macOS对此还不支持。Windows如今也不支持。函数
在咱们开始前,须要确保核心转储的ulimit设置在合适的范围。它的缺省值是0,意味着最大的核心文件大小是0。我一般在个人开发机器上将它设置成unlimited。使用如下命令:post
$ ulimit -c unlimited
接下来,你须要在你的机器上安装delve。网站
下面咱们使用的main.go
文件。它注册了一个简单的请求处理函数(handler)而后启动了HTTP服务。ui
$ cat main.go package main import ( "fmt" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello world\n") }) log.Fatal(http.ListenAndServe("localhost:7777", nil)) }
让咱们编译并生产二进制文件。翻译
$ go build .
如今让咱们假设,这个服务器出了些问题,可是咱们并非很肯定问题的根源。你可能已经在程序里加了不少辅助信息,但仍是没法从这些调试信息中找出线索。一般在这种状况下,当前进程的快照会很是有用。咱们能够用这个快照深刻查看程序的当前状态。debug
有几个方式来获取核心文件。你可能已经熟悉了奔溃转储(crash dumps)。它们是在一个程序奔溃的时候写入磁盘的核心转储。Go语言在缺省设置下不会生产奔溃转储。可是当你把GOTRACEBACK
环境变量设置成“crash”,你就能够用Ctrl+backslash
才触发奔溃转储。以下图所示:
$ GOTRACEBACK=crash ./hello (Ctrl+\)
上面的操做会使程序终止,将堆栈跟踪(stack trace)打印出来,并把核心转储文件写入磁盘。
另外个方法能够从一个运行的程序得到核心转储而不须要终止相应的进程。gcore
能够生产核心文件而无需使运行中的程序退出。
$ ./hello & $ gcore 546 # 546 is the PID of hello.
根据上面的操做,咱们得到了转储而没有终止对应的进程。下一步就是把核心文件加载进delve并开始分析。
$ dlv core ./hello core.546
差很少就这些。delve的经常使用操做均可以使用。你能够backtrace,list,查看变量等等。有些功能不可用由于咱们使用的核心转储是一个快照而不是正在运行的进程。可是程序执行路径和状态所有能够访问。
(dlv) bt 0 0x0000000000457774 in runtime.raise at /usr/lib/go/src/runtime/sys_linux_amd64.s:110 1 0x000000000043f7fb in runtime.dieFromSignal at /usr/lib/go/src/runtime/signal_unix.go:323 2 0x000000000043f9a1 in runtime.crash at /usr/lib/go/src/runtime/signal_unix.go:409 3 0x000000000043e982 in runtime.sighandler at /usr/lib/go/src/runtime/signal_sighandler.go:129 4 0x000000000043f2d1 in runtime.sigtrampgo at /usr/lib/go/src/runtime/signal_unix.go:257 5 0x00000000004579d3 in runtime.sigtramp at /usr/lib/go/src/runtime/sys_linux_amd64.s:262 6 0x00007ff68afec330 in (nil) at :0 7 0x000000000040f2d6 in runtime.notetsleep at /usr/lib/go/src/runtime/lock_futex.go:209 8 0x0000000000435be5 in runtime.sysmon at /usr/lib/go/src/runtime/proc.go:3866 9 0x000000000042ee2e in runtime.mstart1 at /usr/lib/go/src/runtime/proc.go:1182 10 0x000000000042ed04 in runtime.mstart at /usr/lib/go/src/runtime/proc.go:1152 (dlv) ls > runtime.raise() /usr/lib/go/src/runtime/sys_linux_amd64.s:110 (PC: 0x457774) 105: SYSCALL 106: MOVL AX, DI // arg 1 tid 107: MOVL sig+0(FP), SI // arg 2 108: MOVL $200, AX // syscall - tkill 109: SYSCALL => 110: RET 111: 112: TEXT runtime·raiseproc(SB),NOSPLIT,$0 113: MOVL $39, AX // syscall - getpid 114: SYSCALL 115: MOVL AX, DI // arg 1 pid