Skip to content

C++ 调试、Core Dump 与运行期诊断 ​

排查 C++ 问题时,不要只靠“加日志猜原因”。先保留符号和现场,再按崩溃、内存、并发、性能四类问题选择合适工具;不同工具擅长发现不同错误。

故障定位路径 ​

先确认版本、构建产物、输入、线程数和运行环境。线上问题尤其要保留 build ID、可执行文件和匹配的调试符号;拿“另一个版本”的二进制分析 core 往往会得到错误栈。

Core Dump 保存了什么 ​

Core dump 是操作系统在进程异常终止(或显式请求)时保存的进程现场文件,不是“只生成一个调用栈”。其中通常包含寄存器状态、映射内存片段、线程信息、信号原因以及部分栈/堆数据;能否看到局部变量、内联帧和准确源代码位置,取决于调试符号与优化程度。

Linux 中可通过 ulimit -c unlimited 允许 shell 启动的进程生成 core;实际落盘位置和收集方式还受 core_pattern、systemd-coredump、容器权限与磁盘策略影响。core 可能含口令、令牌和用户数据,必须按敏感生产数据管理。

常用 GDB 起点:

bash
gdb ./my_server core
(gdb) bt                 # 当前线程调用栈
(gdb) thread apply all bt # 全部线程调用栈
(gdb) frame 3            # 切换到某一帧
(gdb) info locals        # 查看局部变量(依赖符号与优化)
(gdb) p variable         # 打印表达式

优化构建可能内联函数、消除变量或重排控制流,导致“变量已优化掉”或调用栈不直观。为复现调试可采用 -g -O0;需要更接近线上性能时可用 -g -O1 / -g -O2 并接受部分可观测性下降。

Sanitizer:尽早发现内存与并发问题 ​

工具擅长发现常见编译选项重要限制
AddressSanitizer(ASan)越界访问、use-after-free、栈/堆错误-fsanitize=address增加内存和运行期开销,通常用于测试/灰度
LeakSanitizer(LSan)进程退出时的泄漏常与 ASan 一起启用对常驻全局对象和第三方库需正确解读
UndefinedBehaviorSanitizer(UBSan)有符号溢出、错误转换、部分未定义行为-fsanitize=undefined不能覆盖所有 UB
ThreadSanitizer(TSan)数据竞争与部分同步错误-fsanitize=thread开销较高,通常不能与 ASan 同时使用

示例(Clang / GCC 工具链,具体可用组合以工具链文档为准):

bash
c++ -std=c++20 -g -O1 -fno-omit-frame-pointer \
  -fsanitize=address,undefined app.cpp -o app
ASAN_OPTIONS=detect_leaks=1 ./app

Sanitizer 报告指向的是触发点,根因可能更早:例如 ASan 报 use-after-free 时,需要同时检查对象所有权、异步回调、容器失效和线程停止顺序。

常见问题与首选手段 ​

症状第一选择关键追问
段错误、非法指令、abortcore + GDB + ASan空/悬空指针?数组越界?断言或 terminate?
堆损坏、偶发崩溃ASan、最小化复现更早的越界是否破坏了分配器元数据?
内存持续增长LSan、堆 profile、对象指标真泄漏还是缓存、队列堆积、未释放连接?
随机错结果/偶发死锁TSan、锁顺序、线程栈是否有无锁读写、锁顺序反转、生命周期竞态?
CPU 高或尾延迟升高profiler、火焰图、P95/P99热点是算法、锁竞争、分配、I/O 还是调度?

日志仍重要,但要记录结构化的请求 ID、错误码、状态转换和可控采样;不要把用户密钥、原始密码或完整敏感载荷写入日志。

strace 与系统调用跟踪 ​

strace 的原理与风险:strace 基于 ptrace 系统调用,把目标进程置于被跟踪状态——每次系统调用都要停下目标进程,由 tracer 接管后再恢复。生产环境风险:

  • 系统调用密集的进程可能慢几倍到几十倍(每次 syscall 都多出停止/恢复与上下文切换);
  • 目标被暂停、时序改变,竞态类问题可能消失或恶化(Heisenbug);
  • ptrace 可能被安全机制拒绝(ptrace_scope、容器 seccomp 策略);
  • 输出文件巨大,可能打满磁盘。

更轻量的替代方案:

工具原理适用
perf stat / perf record采样 + 硬件计数器热点分析、火焰图,不改写目标行为
eBPF / bpftrace内核内安全探针(kprobe/tracepoint)按需插桩、可过滤,开销小可灰度
ftrace内核自带跟踪框架内核函数调用跟踪
应用层埋点日志、指标、延迟分布最可控,作为常规手段

一句话:strace 全量拦截系统调用,重且改变时序;生产环境优先 perf/eBPF 等采样式或插桩式方案,strace 只在低流量或非生产环境短暂使用。

面试速答 ​

Linux 程序崩溃如何定位:先确保二进制与调试符号可对应,收集 core 和日志;用 gdb binary core 查看崩溃信号、bt 和全部线程栈,再检查崩溃帧的参数、局部变量与相关对象生命周期。若可复现,使用 ASan/UBSan 运行复现输入;涉及并发时用 TSan 或检查同步、停止与销毁协议。最后修复根因并加入回归测试,而不是只在崩溃点加空指针判断。

使用 Markdown 与 VitePress 构建