go程序默认不生成core文件是设计使然,因其panic由runtime自主栈展开并exit(2),不触发sigabrt/sigsegv等信号,内核无法收到dump请求;仅cgo崩溃、gotraceback=crash或手动raise信号等非原生场景才可能生成core,需配合syscall.setrlimit、系统core_pattern配置及dlv调试。

Go 程序默认不生成 core 文件,这不是配置遗漏或环境问题,是 runtime 设计决定:panic 走自主栈展开 + exit(2),不发 SIGABRT/SIGSEGV,内核根本收不到 dump 请求。
为什么 ulimit -c unlimited 后还是没 core
常见错误现象:ulimit -c unlimited 执行了、/proc/sys/kernel/core_pattern 也设了,程序 panic 或 segfault 后目录下依然空空如也。
根本原因在于:Go 原生 panic 不触发信号机制。只有以下情况才可能落地 core:
- Cgo 调用中触发
abort()、free(NULL)、raise(SIGSEGV)等 libc 行为 - 系统级信号被 Go runtime 未接管(比如用
GOTRACEBACK=crash强制 raise SIGABRT) - CGO_ENABLED=1 且未禁用 libc 调用能力
若编译时加了 -ldflags="-w" 或 CGO_ENABLED=0,syscall.Setrlimit 会直接失败,ulimit -c 也无效——此时 core 生成能力归零。
让非原生崩溃生成可用 core 的三步实操
目标:让 C 层段错误真正落地为 /tmp/core-xxx,能被 dlv 加载还原 goroutine 上下文。
- 设 core 路径:
echo '/tmp/core-%e.%p' | sudo tee /proc/sys/kernel/core_pattern(避免被 systemd-coredump 接管) - 开资源限制:
ulimit -c unlimited,并确认硬限制非 0:ulimit -H -c;若为 0,需改/etc/security/limits.conf - 在
main()最开头插入:syscall.Setrlimit(syscall.RLIMIT_CORE, &syscall.Rlimit{Cur: ^uint64(0), Max: ^uint64(0)}),且必须配环境变量GOTRACEBACK=crash
注意:GOTRACEBACK=crash 是唯一能让 Go 主动交出控制权给内核的开关;缺它,哪怕 C 层崩溃也可能被 runtime 拦截吞掉。
dlv 加载 core 后该看什么
gdb 对 Go core 基本无效——看到的常是 runtime.sigtramp 或空栈帧,因为 goroutine 栈不在 libc 栈上,gdb 不认识 M/P/goroutine 调度结构。
用 dlv core ./app /tmp/core-app.12345 进入后,优先执行:
-
goroutines:列出所有 goroutine,观察哪些处于 running/blocked 状态 -
gr 1(切换到 goroutine 1)+bt:看 panic 前最后一跳调用链 -
locals -v:检查局部变量值,确认是否为nil解引用、除零等直接诱因 -
regs:查看寄存器状态,特别是PC和SP,辅助定位汇编级问题
前提是编译时加了 -gcflags="all=-N -l"(关优化+关内联),否则 locals 可能为空,bt 行号错乱。
真正该盯住的不是 core,而是 panic 前那几秒
线上偶发 panic 往往无日志上下文,等 core 写完再分析,请求参数、时间戳、上下游 traceID 都丢了。core 是兜底手段,不是第一响应路径。
更现实的做法是:在关键入口或 recover 处插桩 runtime.Stack(buf, true),把全 goroutine 栈打到日志;同时开 runtime.SetTraceback("system"),让 panic 输出包含寄存器和完整栈指针——这些信息比一个静态内存镜像更能快速定位根因。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











