Linux Core Dump 完全指南:从原理到实战的崩溃调试手册。什么是core dump?程序报错core dumped怎么办?

跑得好好的程序突然崩溃,终端显示 Segmentation fault (core dumped),没有日志,没有报错堆栈,怎么排查?

目录


一、什么是 Core Dump?

字面含义

  • Core:早期计算机的内存叫"磁芯内存"(Magnetic Core Memory),这个称呼沿用至今,代指程序的内存状态。
  • Dumped:转储、倾倒。

Core Dump 就是当程序发生严重错误崩溃时,操作系统在进程退出前,将其当时的内存状态、寄存器值、函数调用栈、局部变量等所有运行信息,完整保存到一个文件(通常叫 core)中的过程。

核心价值

  1. 事后调试:无需复现崩溃场景,直接分析 core 文件就能找到崩溃点
  2. 保留现场:即使程序已经退出,也能查看崩溃瞬间的所有变量值、函数调用链
  3. 排查偶发 Bug:对于随机崩溃的问题,只要拿到 core 文件就能稳定分析,不用再"等它再崩一次"

二、什么时候会触发 Core Dump?

当程序收到以下未捕获的信号时,系统会自动触发 core dump:

信号 含义 常见触发场景
SIGSEGV 段错误 空指针解引用、数组越界、访问已释放内存
SIGABRT 主动中止 调用 abort()、assert 断言失败
SIGBUS 总线错误 内存对齐错误、硬件故障
SIGFPE 算术异常 整数除以 0、浮点运算溢出
SIGILL 非法指令 执行了 CPU 不支持的指令、二进制文件损坏

三、从 0 到 1 开启 Core Dump

第一步:检查当前是否开启

bash 复制代码
ulimit -c
  • 输出 0:表示关闭,不会生成 core 文件
  • 输出 unlimited 或具体数字:表示已开启

第二步:临时开启(仅当前终端会话有效)

bash 复制代码
ulimit -c unlimited

第三步:永久开启(所有用户生效)

编辑 /etc/security/limits.conf,添加以下两行:

复制代码
* soft core unlimited
* hard core unlimited

如果崩溃的程序是 systemd 管理的服务,需要在对应的 service 文件中添加:

复制代码
[Service]
LimitCORE=infinity

第四步:配置 core 文件的存储路径和命名规则

默认的 core 文件可能在当前目录生成,也可能被 systemd 接管。如果想自定义存储位置和文件名,修改内核参数 core_pattern:

临时生效:

bash 复制代码
sudo sysctl -w kernel.core_pattern=/var/crash/core-%e-%p-%t

永久生效 :

在 /etc/sysctl.conf 中添加:

复制代码
kernel.core_pattern=/var/crash/core-%e-%p-%t

常用占位符说明:

占位符 含义
%e 可执行文件名
%p 进程 PID
%t 崩溃时的时间戳(秒)
%u 进程用户 ID
%s 触发崩溃的信号编号
%h 主机名

注意:提前创建存储目录并设置写权限,否则 core 文件无法生成:

bash 复制代码
sudo mkdir -p /var/crash
sudo chmod 777 /var/crash

四、调试前的必备准备:编译时加调试符号

这一步非常重要! 如果编译时没有添加调试信息,gdb 只能看到内存地址,无法显示对应的源码行号和变量名,core 文件基本等于废了。

编译时必须添加 -g 参数,建议同时用 -O0 关闭优化,避免优化后代码行号和实际执行位置对不上:

bash 复制代码
gcc -g -O0 -o my_app my_app.c

如果是 CMake 项目,设置构建类型为 Debug 即可:

cmake 复制代码
set(CMAKE_BUILD_TYPE Debug)

五、实战:用 GDB 分析 Core Dump

1. 准备示例代码

我们写一个会触发段错误的程序:

c 复制代码
// crash_demo.c
#include <stdio.h>

int main() {
    int *ptr = NULL;
    printf("即将访问空指针...\n");
    *ptr = 42;  // 空指针解引用,触发 SIGSEGV
    return 0;
}

2. 编译并运行

bash 复制代码
gcc -g -O0 -o crash_demo crash_demo.c
./crash_demo

输出:

复制代码
即将访问空指针...
段错误 (核心已转储)

3. 找到 core 文件

根据刚才配置的 core_pattern,core 文件应该在 /var/crash/ 目录下,文件名类似 core-crash_demo-12345-1629876543。

4. 用 GDB 加载分析

bash 复制代码
gdb ./crash_demo /var/crash/core-crash_demo-12345-1629876543

进入 gdb 交互界面后,常用命令如下:

查看崩溃调用栈

gdb 复制代码
(gdb) bt
#0  0x0000555555555149 in main () at crash_demo.c:6
6           *ptr = 42;  // 空指针解引用,触发 SIGSEGV

栈顶的 #0 就是崩溃发生的具体位置,直接定位到第 6 行代码。

查看变量值

gdb 复制代码
(gdb) print ptr
$1 = (int *) 0x0

可以看到 ptr 的值是 0x0,确认是空指针解引用导致的问题。

其他常用命令

gdb 复制代码
frame 0             # 切换到第 0 层栈帧(崩溃点)
info locals         # 查看当前函数所有局部变量
list                # 查看崩溃点附近的源码
info registers      # 查看 CPU 寄存器状态

如果是多线程程序,还可以用:

gdb 复制代码
info threads        # 查看所有线程状态
thread 2            # 切换到第 2 个线程
thread apply all bt # 打印所有线程的调用栈

六、现代 Linux 的 Core Dump 管理:systemd-coredump

现在很多主流发行版(Ubuntu 20.04+、CentOS 8+、Debian 11+)默认使用 systemd-coredump 接管 core 文件,不会在当前目录生成 core 文件,而是统一存储到 /var/lib/systemd/coredump/ 下,用 coredumpctl 工具管理:

bash 复制代码
coredumpctl list           # 查看所有 core dump 记录
coredumpctl info           # 查看最近一次崩溃的详情
coredumpctl debug          # 直接用 gdb 调试最近的崩溃
coredumpctl debug <PID>    # 调试指定 PID 的 core 文件

七、生产环境避坑指南

1. 安全问题

core 文件里可能包含密码、API 密钥、用户数据等敏感信息,绝对不能传到公开的地方,分析完成后及时删除,建议设置文件权限为 600:

bash 复制代码
chmod 600 /var/crash/core-*

2. 磁盘空间

core 文件的大小和程序占用的内存差不多,可能达到几 GB 甚至几十 GB,容易把磁盘撑爆。可以设置大小限制:

bash 复制代码
ulimit -c 102400  # 限制 core 文件最大为 100MB

或者定期清理旧的 core 文件:

bash 复制代码
find /var/crash -name "core.*" -mtime +7 -delete

3. 找不到 core 文件?排查步骤

  • 检查 ulimit -c 是否开启
  • 检查 core_pattern 配置的路径是否有写权限
  • 检查磁盘空间是否满了
  • 如果是 setuid 程序,需要设置 fs.suid_dumpable=2

4. GDB 加载 core 文件显示 ?? 没有行号?

  • 检查编译时是否加了 -g 参数
  • 检查加载的可执行文件和崩溃时的是不是同一个版本,不能重新编译后再分析旧的 core 文件,否则符号表对不上
相关推荐
_upupup6 小时前
Linux的调试工具——gdb/cgdb
linux·服务器
JeJe同学7 小时前
Docker镜像导入、容器启动
linux·运维·docker
Jason_zhao_MR7 小时前
Linux与实时控制如何兼得
linux·嵌入式硬件·机器人·工业控制
闲云野鹤在人间8 小时前
MySQL|从理论、安装、备份到主从复制、MHA高可用详解
linux·运维·数据库·mysql·云计算
一个风轻云淡9 小时前
GCC 和 GDB命令简单解读
java·linux·前端
H.莓飛9 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
资料库019 小时前
Linux 8个常见运维故障排查
java·linux·运维
零基础12310 小时前
Ubuntu 常用命令汇总
linux·运维·开发语言
Android系统攻城狮10 小时前
Linux Gstreamer深度解析之gst_audio_sink_get_type调用流程与实战(六十五)
linux·运维·服务器·音视频·gstreamer音视频·音视频进阶·gstreamer音视频进阶
xiaoqiMikko10 小时前
Linux 实战(一):CentOS 7、Rocky 9、Ubuntu 24.04 三台真机实测 —— 认清系统、换源、装包的版本坑
linux·centos