Go:一次 exit code 是 137 且 无 coredump 的排错经历
最近在调试一个 Go 写的网关,总是莫名其妙地出现重启。
我以为是我写代码有 BUG 引发 panic 导致进程退出,我想借助 coredump 定位问题。
但是,在我设置如下后:
1.$ ulimit -c unlimited
2.$ export GOTRACEBACK=crash
更多参考:https://blog.csdn.net/test1280/article/details/112570784
在进程异常退出时,我没能找到 panic 输出,也没找到 coredump,如下:
...(一些前台终端日志输出)
已杀死
$
初时,我以为是 ulimit -c 或是 GOTRACEBACK 有问题,但是单独执行:
package main
func main() {
panic("test1280-panic info")
}
$ go run main.go
panic: test1280-panic info
goroutine 1 [running]:
panic(0x466460, 0x48a298)
...
signal: aborted (core dumped)
$ file core*
core.25321: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from '/tmp/go-build3230483068/b001/exe/main'
可以正常地、如期地在 panic 时生成 coredump 文件。
可见并非是 ulimit -c 或 GOTRACEBACK 设置问题引起。
那问题就是在代码本身?
紧接着我又查看了 exit code。
我们知道,进程在消亡时,总会有一个 exit code 存在,记录进程消亡原因。
通过 echo $?
可以查看上一个命令(进程)的 exit code。
我是将此网关启动在前台,等网关进程异常退出,然后执行 echo $?
:
$ ./gateway
...(一些前台终端日志输出)
已杀死
$ echo $?
137
关键线索:退出码 137!
Google:golang exit code 137 no coredump
我查到一个提问:Process finished with exit code 137 in PyCharm
里面有一个回复:
Exit code 137 means that your process was killed by (signal 9) SIGKILL.
In most of the cases, it is caused by excessive memory usage.
exit code = 137,且 “已杀死”,指的是进程被 SIGKILL 信号干掉了。
而大多数情况下是因为内存使用超标导致(OOM),操作系统使用 SIGKILL 杀死进程。
!!!醍醐灌顶。赶快测试:
一边 tail -f /var/log/messages
,一边启动网关复现问题,果不其然,稍等片刻:
Feb 16 16:00:32 test1280 kernel: Out of memory: Kill process 20820 (gateway) score 100 or sacrifice child
Feb 16 16:00:32 test1280 kernel: Killed process 20820 (gateway) total-vm:3675256kB, anon-rss:804648kB, file-rss:124kB, shmem-rss:0kB
当前系统内存占用:【free 133MB】
$ free -h
total used free shared buff/cache available
Mem: 7.6G 6.1G 133M 13M 1.4G 762M
Swap: 0B 0B 0B
真相终于揭晓:
并非是 Go 写的网关代码存在BUG,而是:
网关占用本剩余不多的内存触发OOM(虽然网关占用内存很少),被操作系统SIGKILL杀死。
被 SIGKILL 杀死,当然是没有 coredump 的。
用 C 复现测试一下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 1024*1024*1024
int main()
{
void *p = malloc(SIZE);
memset(p, 0, SIZE);
sleep(60);
return 0;
}
$ gcc -o main main.c
$ ./main
已杀死
$
此时,/var/log/message 可以观察到:
Feb 16 17:26:58 test1280 kernel: Out of memory: Kill process 28012 (main) score 98 or sacrifice child
Feb 16 17:26:58 test1280 kernel: Killed process 28012 (main) total-vm:1052748kB, anon-rss:788564kB, file-rss:52kB, shmem-rss:0kB
如果降低内存申请:(SIZE 由 1G 改为 10B)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 10
int main()
{
void *p = malloc(SIZE);
memset(p, 0, SIZE);
sleep(60);
return 0;
}
$ gcc -o main main.c
$ ./main
$ 【sleep 60s 后正常结束】
总结:
如果你的代码在运行时异常退出且出现“已杀死”,查看 exit code 是 137 时:
不一定是你的代码有 BUG,可能是操作系统内存不足,你的进程被 OOM kill 掉啦。
赶快检查下 /var/log/message 吧!
https://stackoverflow.com/a/50910479
https://stackoverflow.com/questions/43268156/process-finished-with-exit-code-137-in-pycharm
后记
后面发现,确实是我写的网关有内存泄漏问题,占用大约2GB内存。