GDB需配合-g编译才能定位源码行:崩溃时用bt看调用栈,info registers查寄存器值,print查变量,handle SIGSEGV stop捕获段错误,MALLOC_CHECK_=2检测堆破坏,gcore手动抓快照。

段错误发生后,GDB怎么立刻知道哪行崩的
直接用 gdb ./your_program 启动,再用 run 运行,崩了就停在出错指令处——但这时看到的往往是汇编地址,不是源码行。关键在编译时必须带调试信息:gdb 不会自己“猜”源码位置。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 编译命令必须加
-g,比如g++ -g -o main main.cpp;不加的话gdb只能显示寄存器和内存地址,看不到变量名、函数名、行号 - 如果程序已崩溃退出(比如 core dump),用
gdb ./your_program core加载 core 文件,再执行bt(backtrace)看调用栈 - 某些系统默认禁用 core dump,先运行
ulimit -c unlimited再跑程序,否则压根没 core 文件可查
为什么 bt 有时只显示 ?? 或一堆问号
这是符号缺失的典型表现,说明 gdb 找不到对应函数的调试信息。常见于链接了未带 -g 的静态库、或用了 stripped 的系统库。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 检查是否误用了
strip ./your_program—— strip 会删掉所有调试符号,gdb就彻底“失明” - 若依赖第三方静态库(如
libxxx.a),确认它也是用-g编译的;否则即使你的代码有调试信息,调用到库内部也会断在?? -
file ./your_program在gdb里执行,看输出里有没有 “with debug_info” 字样,没有就是白忙活
用 print 和 info registers 看清崩溃瞬间发生了什么
段错误本质是访问了非法内存地址(比如空指针解引用、野指针、栈溢出、越界写数组),光看 bt 不够,得确认当时寄存器里存的是啥、想读/写的地址到底是多少。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 崩停后立即输
info registers,重点看rip(下一条指令地址)、rax/rdi等寄存器值;如果rdi是0x0,大概率是空指针调用 - 用
print /x $rdi查看寄存器十六进制值;用x/10xb $rdi尝试读取该地址附近 10 字节内存(可能触发二次段错误,慎用) - 如果崩溃在
std::vector::at()或std::string::operator[],配合print v._M_impl._M_finish类似路径,能定位容器实际边界
core dump 太大?或者根本不想等它崩,想提前卡住
靠等段错误发生再调试太被动。更稳的方式是让程序一碰非法内存就停住,而不是直接退出。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 在
gdb里运行前加handle SIGSEGV stop print,这样收到段错误信号时不会退出,而是暂停并打印信息 - 如果怀疑是堆破坏(比如
free后还写),启动时用set environment MALLOC_CHECK_ 2(Linux glibc),能提前报错 - core 文件太大影响分析?用
gcore命令手动抓当前进程快照:gcore -o mycore `pidof your_program`,比等自然崩溃更可控
最常被忽略的一点:C++ 中 std::shared_ptr 循环引用、std::vector 迭代器失效、std::string data() 返回的指针在 string 被移动后失效——这些都不会报编译错误,但会在运行时随机段错误,且 gdb 只能告诉你“这里崩了”,没法自动指出“因为上一行 move 了 string”。得结合代码逻辑反推。








