一、Core 分析解决的是什么问题

程序运行过程中,可能出现两类完全不同的问题。

第一类是程序自己记录下来的错误,例如:

连接数据库失败
文件不存在
权限不足
SQL语法错误
磁盘空间不足

这类问题一般会被写入运行日志。程序通常还能控制错误处理过程,因此日志里可能明确记录错误码、错误描述和发生时间。

第二类是程序本身突然失去正常执行能力,例如:

访问了不存在的内存地址
使用了已经释放的内存
发生除零
执行了非法指令
内部断言失败
某个动态库异常退出
线程栈溢出

程序可能来不及把详细原因写入日志,就被操作系统终止。

这时,运行日志最多可能只留下:

程序异常退出
Segmentation fault
signal 11

但我们真正想知道的是:

哪个线程出了问题?
程序执行到了哪个函数?
这个函数是被谁调用的?
当时函数参数是什么?
访问了哪个内存地址?
关键寄存器里是什么值?
崩溃发生在主程序还是动态库?

Core Dump 的作用,就是尽可能保存程序异常时的现场。

GDB 的作用,则是读取和解释这个现场。

可以先用一句话记忆:

Core 是事故现场,GDB 是勘查事故现场的工具。


二、Core Dump 是什么

Core Dump 中文常译为:

  • 核心转储;
  • 内存转储;
  • 进程崩溃快照;
  • Core 文件。

它通常是一个二进制文件。

当程序收到某些会导致异常终止的信号时,Linux 内核可以将程序当时的部分内存映像和进程状态写入 Core 文件。GDB 官方将 Core 描述为运行进程的内存映像和进程状态记录,包括寄存器值等,其主要用途是对已经崩溃的程序进行事后调试。

例如:

dmserver正在执行SQL
        ↓
某个线程访问非法内存
        ↓
CPU产生异常
        ↓
Linux向进程发送SIGSEGV
        ↓
dmserver异常终止
        ↓
Linux尝试生成Core文件

Core 不是普通日志,因此不能用下面的方法正常阅读:

cat core文件
vi core文件
less core文件

即使强行打开,看到的也主要是不可读的二进制内容。

Core 需要交给 GDB 等调试工具解释。


三、Core、日志和 Redo 的区别

数据库场景里,最容易把以下几种信息混在一起。

信息 记录的内容 主要用途
数据库运行日志 启停、错误、警告和运行事件 判断崩溃前发生过什么
操作系统日志 OOM、磁盘、文件系统、内核和硬件信息 判断是否为系统层问题
Core 文件 进程异常瞬间的内存和执行现场 分析进程为什么崩溃
Redo 日志 数据库修改记录 实例恢复和事务一致性
数据库备份 数据文件的可恢复副本 数据库还原与恢复

例如,dmserver 因程序缺陷突然退出后,可能同时发生:

生成Core
    → 用来调查dmserver为什么崩溃

重新启动时读取Redo
    → 用来恢复未完成的数据写入

因此:

Core 解决“程序为什么死”,Redo 解决“程序死后数据库怎样恢复一致”。

Core 不能代替数据库备份,也不能用来还原数据。


四、GDB 是什么

GDB 全称是:

GNU Debugger

它是 GNU 提供的程序调试器。

GDB 的用途并不局限于 Core,它有三种常见工作模式。

1. 调试即将运行的程序

gdb ./core_lab

进入 GDB 后:

run

此时程序在 GDB 控制下运行。

可以:

  • 设置断点;
  • 单步执行;
  • 查看变量;
  • 修改变量;
  • 查看寄存器;
  • 查看内存;
  • 观察函数调用。

这种方式适合开发人员调试能够复现的问题。


2. 附加到正在运行的程序

gdb -p PID

例如:

gdb -p 12345

GDB 会附加到 PID 为 12345 的进程。

这种方式可以用于分析:

  • 程序卡死;
  • 线程长时间等待;
  • CPU 异常占用;
  • 某个进程还活着,但没有响应。

不过,GDB 附加进程期间通常会暂停被调试进程,因此生产环境必须谨慎。


3. 分析已经生成的 Core

gdb 可执行文件 Core文件

例如:

gdb /dmdbms/bin/dmserver \
    /dmdata/core/core-dmserver-12345

这表示:

用dmserver可执行文件及其符号信息
解释Core文件中的内存和进程状态

这就是最常见的 Core 事后分析模式。


五、为什么有了 Core,还需要原来的可执行程序

Core 里面保存的大量信息,本质上是地址和原始数据。

例如:

当前执行地址:0x00000000014a52c0

只看这个地址,我们不知道它代表什么。

GDB 需要结合对应版本的可执行文件,将地址映射成:

某个函数
某个模块
某条机器指令
可能的源代码行

GDB 在分析 Core 时,会把 Core 作为内存内容,同时从可执行文件中读取程序代码、只读段和符号信息。因此,传统 Core 通常只保存地址空间的一部分,其他内容需要从原始可执行文件补充。

理想的 Core 分析材料包括:

Core文件
+
崩溃时对应版本的可执行程序
+
对应版本的动态库
+
对应的调试符号文件

如果发生崩溃后数据库进行了升级,再拿新版本的 dmserver 分析旧 Core,可能出现:

  • 函数地址对应错误;
  • 堆栈无法展开;
  • 函数名混乱;
  • 动态库地址不匹配;
  • GDB 显示大量问号;
  • 分析结论不可信。

所以现场处理中,不能只保留 Core,还应尽量保留故障时的程序版本、动态库和补丁信息。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐