Core Dump 文件:配置生成、ulimit 设置、gdb 加载核心文件

调试 crash 最有力的武器是什么?我个人觉得就是 core dump。说白了,程序崩溃那一瞬间的内存快照,里面包含了调用栈、变量值、寄存器状态。拿到它,就能还原事故现场。我曾经在线上追一个偶现的段错误,靠 core dump 十分钟定位,比打 log 重新跑快太多了。这章我们就把它彻底搞明白。

什么是 core dump?

当程序收到 SIGSEGV、SIGABRT 这类致命信号时,操作系统会把进程的内存映像写到磁盘上,这个文件就叫 core dump。默认文件名就是 core,当然也可以配成 core.进程号 之类。你想想看,如果没这个文件,你只能靠 log 脑补现场,多痛苦。

配置生成 core dump

系统有两个关键开关:

  • 是否允许生成:由 /proc/sys/kernel/core_uses_pid 控制,写 1 表示文件名追加 PID。
  • 文件路径和格式:/proc/sys/kernel/core_pattern 控制。默认是 core,你可以改成 /tmp/core_%e_%p 这样更清晰。

核心命令:检查当前配置

cat /proc/sys/kernel/core_pattern
cat /proc/sys/kernel/core_uses_pid

临时修改(重启失效):

echo "/home/core/%e_%p_%t" > /proc/sys/kernel/core_pattern
echo 1 > /proc/sys/kernel/core_uses_pid

我习惯把 core 文件统一放在 /var/crash 目录,按程序名和时间命名,方便集中管理。你最好也开一个独立目录,别让 core 污染项目根路径。

ulimit 设置

光配置了系统层还不够,shell 层还有一个限制:ulimit -c。默认很多服务器是 0,也就是不生成 core。你得先把这个打开。

ulimit -c 值含义
0完全不生成 core
unlimited无大小限制,推荐
特定数字(如 1048576)只允许 core 文件最大 1MB,可能会导致文件被截断

记忆小技巧:调试阶段直接 ulimit -c unlimited,生产环境可以设一个上限防止磁盘爆满。但千万别设 0,否则 crash 后你连后悔的机会都没有。

永久设置?修改 /etc/security/limits.conf:

# 针对所有用户,soft 和 hard 都设为无限制
*               soft    core            unlimited
*               hard    core            unlimited

然后重新登录生效。我曾见过有人只在 shell 里设了 ulimit,但服务是通过 systemd 启动的,结果 core 出不来。systemd 服务要单独配置 LimitCore=infinity。

gdb 加载 core 文件

拿到 core 文件后,用 gdb 一把梭:

gdb /path/to/program /path/to/core

进入 gdb 后,第一个命令就是 bt(backtrace),看调用栈:

(gdb) bt
#0  0x00007f... in __memmove_avx_unaligned_erms ()
#1  0x00004... in my_func (p=0x0) at source.c:123
#2  0x00005... in main () at source.c:456

看到 p=0x0 了吧?空指针访问,一眼丁真。你还可以 frame N 切到指定栈帧,用 info locals 看局部变量,用 p variable 打印变量值。

注意:编译时一定要加 -g 选项保留符号。如果没有符号,gdb 只能看到地址和偏移,定位难度大增。我前公司有个历史遗留模块,偏偏没开 -g,每次 core 都得反汇编猜,血的教训。

实战案例:定位一个空指针 crash

假设你有一个程序 server 崩溃了,生成了 core.12345:

  1. 检查 ulimit -c 和 core_pattern,确保下次还能生成。
  2. gdb ./server core.12345 加载。
  3. bt 看到 crash 在 process_request 函数。
  4. frame 3 切进去,info locals 发现 request == NULL。
  5. 回看源码,原来是没判空就解引用了。修复完,问题解决。

整个过程不到五分钟。这就是 core dump 的威力。

避坑指南

  • 文件权限:core 文件默认 0644,但服务可能以低权限用户运行,导致无法写入。确保目标目录可写。
  • 磁盘空间:core 文件可能很大(尤其多线程、大内存服务)。我建议设置 ulimit -c 104857600(100MB),既能定位问题又不会撑爆磁盘。
  • 重复覆盖:如果不加 PID 或时间戳,多次 crash 会互相覆盖。设置 core_uses_pid=1 或自定义 pattern 带 %p、%t。
  • 容器环境:Docker 容器默认可能不开启 core dump,需要 --privileged 或手动挂载 /proc/sys。

我的习惯:在项目根目录写一个 init_core.sh 脚本,每次调试前运行,确保环境一致。省得每次都去配。

Core Dump 生成与分析流程 程序崩溃 发送 SIGSEGV 等 ulimit -c 检查 core 大小 > 0? 是 否 生成 core 文件 不生成 core gdb 加载 core 定位崩溃行 💡 提示:ulimit -c 设为 unlimited 才能生成完整 core 默认路径:当前目录/core

最后强调一点:拿到 core 后先别急着格式化,备份一份到存档。同一个 bug 可能不同环境表现不一样,多份 core 对分析干扰因素很有帮助。好了,到这里,core dump 的配置、生成、加载、定位你已经全掌握了。