调试Go语言的核心转储(Core Dumps)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调试Go语言的核心转储(Core Dumps)相关的知识,希望对你有一定的参考价值。

参考技术A

英文原文链接【Go, the unwritten parts】 发表于2017/05/22 作者JBD是Go语言开发小组成员

检查程序的执行路径和当前状态是非常有用的调试手段。核心文件(core file)包含了一个运行进程的内存转储和状态。它主要是用来作为事后调试程序用的。它也可以被用来查看一个运行中的程序的状态。这两个使用场景使调试文件转储成为一个非常好的诊断手段。我们可以用这个方法来做事后诊断和分析线上的服务(production services)。

在这篇文章中,我们将用一个简单的hello world网站服务作为例子。在现实中,我们的程序很容易就会变得很复杂。分析核心转储给我们提供了一个机会去重构程序的状态并且查看只有在某些条件/环境下才能重现的案例。

作者注 : 这个调试流程只在Linux上可行。我不是很确定它是否在其它Unixs系统上工作。macOS对此还不支持。Windows现在也不支持。

在我们开始前,需要确保核心转储的ulimit设置在合适的范围。它的缺省值是0,意味着最大的核心文件大小是0。我通常在我的开发机器上将它设置成unlimited。使用以下命令:

接下来,你需要在你的机器上安装 delve 。

下面我们使用的 main.go 文件。它注册了一个简单的请求处理函数(handler)然后启动了HTTP服务。

让我们编译并生产二进制文件。

现在让我们假设,这个服务器出了些问题,但是我们并不是很确定问题的根源。你可能已经在程序里加了很多辅助信息,但还是无法从这些调试信息中找出线索。通常在这种情况下,当前进程的快照会非常有用。我们可以用这个快照深入查看程序的当前状态。

有几个方式来获取核心文件。你可能已经熟悉了奔溃转储(crash dumps)。它们是在一个程序奔溃的时候写入磁盘的核心转储。Go语言在缺省设置下不会生产奔溃转储。但是当你把 GOTRACEBACK 环境变量设置成“crash”,你就可以用 Ctrl+backslash 才触发奔溃转储。如下图所示:

上面的操作会使程序终止,将堆栈跟踪(stack trace)打印出来,并把核心转储文件写入磁盘。

另外个方法可以从一个运行的程序获得核心转储而不需要终止相应的进程。 gcore 可以生产核心文件而无需使运行中的程序退出。

根据上面的操作,我们获得了转储而没有终止对应的进程。下一步就是把核心文件加载进delve并开始分析。

差不多就这些。delve的常用操作都可以使用。你可以backtrace,list,查看变量等等。有些功能不可用因为我们使用的核心转储是一个快照而不是正在运行的进程。但是程序执行路径和状态全部可以访问。

核心转储core dump

core dump是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。这种信息往往用于调试(事后调试)。

常见的异常终止的情况比如说内存错误(非法访问内存),此时进程收到的信号是SEGSEGV信号,再例如发生除零错误,此时进程收到的信号是SIGFPE

一旦程序发生上面错误而异常终止,在满足一定条件下可以生成core文件,文件通常在可执行程序的路径下

操作系统默认不允许产生core文件,通过 ulimit -a 来确认是否会产生core文件。

我们可以修改core文件的大小,通过ulimit -c [大小]来修改。允许core文件最大的大小为1024kb

现在可以测试一下效果

 对空指针进行解引用,这样会出现内存错误

int main()

    int *p=NULL;
    cout<<*p<<endl;//内存非法访问
    return 0;

此时文件路径下多了一个core.xxx的文件。

注意,生成可执行程序之前的命令记得带上-g。

怎么查看core文件的信息呢?

此时需要用到gdb命令

我们看到这个程序是被11号信号终止(11号信号就是SEGSEGV),报错的行在第9行的代码。 

同样的其他的错误也可以被捕捉到

例如除0错误

 

以上是关于调试Go语言的核心转储(Core Dumps)的主要内容,如果未能解决你的问题,请参考以下文章

使用 cgo 构建时如何调试/转储 Go 变量?

go语言核心学习 14-15 - 程序员学点xx 55

核心转储core dump

核心转储core dump

核心转储core dump

Go -- 如何使用gcore工具获取一个core文件而不重启应用?