golang使用core dump分析定位程序崩溃问题
一、前言
core dump 是一个包含着意外终止的程序其内存快照的文件。这个文件可以被用来事后调试(debugging)以了解为什么会发生崩溃,同时了解其中涉及到的变量。通过 GOTRACEBACK,Go 提供了一个环境变量用于控制程序崩溃时生成的输出信息。这个变量同样可以强制生成 core dump,从而使调试成为可能。
1.1 GOTRACEBACK
GOTRACEBACK 控制程序崩溃时输出的详细程度。它可以采用不同的值:
-
none不显示任何goroutine栈trace。 -
single, 默认选项,显示当前goroutine栈trace。 -
all显示所有用户创建的goroutine栈trace。 -
system显示所有goroutine栈trace,甚至运行时的trace。 -
crash类似system, 而且还会生成 core dump。
二、功能设置
2.1 系统设置
开启core dump 功能:
ulimit -c unlimited
设置core file size = unlimited,core dump file 的文件的大小无限制。也可以根据自己的需要把core file 设置为特定的大小如:
ulimit -c 1024
需要注意的是core file size 的单位是block, block = 512字节。因通过ulimit 设置core file size 只对当前的终端起作用,当你关闭终端或者重启系统设置会失效。为了避免每次都设置的麻烦,可以在~/.profile 最后添加:
echo "ulimit -c unlimited" >> ~/.profile
设置core dump 文件的位置
*kernel.core_pattern=/var/core/core%t%p_%e*
执行:
sysctl -p /etc/sysctl.conf
2.2 GO设置
设置Go环境变量
export GOTRACEBACK=crash
需要注意的是和ulmit 命令一样,在关闭终端和重启系统后,设置的GOTRACEBACK变量会消失,所以要将’export GOTRACEBACK=crash’ 加入到 .profile文件中
echo "export GOTRACEBACK=crash " >> ~/.profile
三、案例分析
GOTRACEBAK变量可以控制程序在崩溃时,stack的输出情况。下面结合具体地程序来分析。
package mainimport ("time""github.com/astaxie/beego/logs")func main() {logs.Info("Start...")defer logs.Info("exit.")i := 0c := make(chan int, 1)for {go func(i int) {mem := make([]int, 100*1024*1024)logs.Info("i=%d,mem:%p", i, mem)mem[0] = <-c}(i)i++time.Sleep(200 * time.Microsecond)}}
该程序将很快崩溃,产生如下报错:
goroutine 279 [running]:goroutine running on other thread; stack unavailablecreated by main.maingoroutine 290 [running]:goroutine running on other thread; stack unavailablecreated by main.mainAborted (core dumped)
gdb可以进行调试,查看程序运行的详细情况:
gdb testcoredump core.15956GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7Copyright (C) 2013 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"...(gdb) startTemporary breakpoint 1 at 0x618c50: file /opt/gopath/src/test/coredump_test/testcoredump.go, line 9.Starting program: /opt/gopath/src/test/coredump_test/testcoredump[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib64/libthread_db.so.1".[New Thread 0x7ffff77f1700 (LWP 15980)][New Thread 0x7ffff6ff0700 (LWP 15981)][New Thread 0x7ffff5fee700 (LWP 15983)][New Thread 0x7ffff67ef700 (LWP 15982)][New Thread 0x7ffff57ed700 (LWP 15984)]Temporary breakpoint 1, main.main () at /opt/gopath/src/test/coredump_test/testcoredump.go:99 func main() {(gdb)
gdb常用命令:
start //开始调试n //一条一条执行step/s //执行下一条,如果函数进入函数backtrace/bt //查看函数调用栈帧info/i locals //查看当前栈帧局部变量frame/f //选择栈帧,再查看局部变量print/p //打印变量的值finish //运行到当前函数返回set var sum=0 //修改变量值list/l 行号或函数名 //列出源码display/undisplay sum //每次停下显示变量的值/取消跟踪break/b 行号或函数名 //设置断点continue/c //连续运行info/i breakpoints //查看已经设置的断点delete breakpoints 2 //删除某个断点disable/enable breakpoints 3 //禁用/启用某个断点break 7 if ok == true //满足条件才激活断点run/r //重新从程序开头连续执行watch input[7] //设置观察点info/i watchpoints //查看设置的观察点x/7b input //打印存储器内容,b--每个字节一组,7--7组disassemble //反汇编当前函数或指定函数si // 一条指令一条指令调试 而 s 是一行一行代码info registers // 显示所有寄存器的当前值x/20 $esp //查看内存中开始的20个数
四、总结
程序崩溃可以通过coredump详细地查看程序调用栈的相关信息,可以更迅速的定位到程序的问题,特别是引起程序崩溃的bug:内存泄漏,一些panic等,当然在写程序时尽量多些log更方便调试。golang自带的pprof在涉及到c库的调用时,会监测不到,这时coredump结合gdb进行调试会比较有用。

浙公网安备 33010602011771号