Go:一次 exit code 是 137 且 无 coredump 的排错经历

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内存。

猜你喜欢

转载自blog.csdn.net/test1280/article/details/122966891